home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / xampp-win32-1.6.5-installer.exe / php / PEAR / go-pear.phar < prev    next >
Encoding:
Text File  |  2007-12-20  |  3.2 MB  |  87,518 lines

Text Truncated. Only the first 1MB is shown below. Download the file for the complete contents.
  1. <?php #PHP_ARCHIVE_HEADER-0.8.0
  2. error_reporting(E_ALL);
  3. if (function_exists('mb_internal_encoding')) {
  4.     mb_internal_encoding('ASCII');
  5. }
  6. if (!class_exists('PHP_Archive')) {/**
  7.  * PHP_Archive Class (implements .phar)
  8.  *
  9.  * @package PHP_Archive
  10.  * @category PHP
  11.  */
  12. /**
  13.  * Flag for GZ compression
  14.  */
  15. define('PHP_ARCHIVE_COMPRESSED', 1);
  16. /**
  17.  * PHP_Archive Class (implements .phar)
  18.  *
  19.  * PHAR files a singular archive from which an entire application can run.
  20.  * To use it, simply package it using {@see PHP_Archive_Creator} and use phar://
  21.  * URIs to your includes. i.e. require_once 'phar://config.php' will include config.php
  22.  * from the root of the PHAR file.
  23.  *
  24.  * Gz code borrowed from the excellent File_Archive package by Vincent Lascaux.
  25.  *
  26.  * @copyright Copyright David Shafik and Synaptic Media 2004. All rights reserved.
  27.  * @author Davey Shafik <davey@synapticmedia.net>
  28.  * @author Greg Beaver <cellog@php.net>
  29.  * @link http://www.synapticmedia.net Synaptic Media
  30.  * @version Id: Archive.php,v 1.33 2006/07/18 23:31:47 cellog Exp $
  31.  * @package PHP_Archive
  32.  * @category PHP
  33.  */
  34.  
  35. class PHP_Archive
  36. {
  37.     /**
  38.      * Whether this archive is compressed with zlib
  39.      *
  40.      * @var bool
  41.      */
  42.     private $_compressed;
  43.     /**
  44.      * @var string Real path to the .phar archive
  45.      */
  46.     private $_archiveName = null;
  47.     /**
  48.      * Current file name in the phar
  49.      * @var string
  50.      */
  51.     protected $currentFilename = null;
  52.     /**
  53.      * Length of current file in the phar
  54.      * @var string
  55.      */
  56.     protected $internalFileLength = null;
  57.     /**
  58.      * Current file statistics (size, creation date, etc.)
  59.      * @var string
  60.      */
  61.     protected $currentStat = null;
  62.     /**
  63.      * @var resource|null Pointer to open .phar
  64.      */
  65.     protected $fp = null;
  66.     /**
  67.      * @var int Current Position of the pointer
  68.      */
  69.     protected $position = 0;
  70.  
  71.     /**
  72.      * Map actual realpath of phars to meta-data about the phar
  73.      *
  74.      * Data is indexed by the alias that is used by internal files.  In other
  75.      * words, if a file is included via:
  76.      * <code>
  77.      * require_once 'phar://PEAR.phar/PEAR/Installer.php';
  78.      * </code>
  79.      * then the alias is "PEAR.phar"
  80.      * 
  81.      * Information stored is the actual file name, a boolean indicating whether
  82.      * this .phar is compressed with zlib, and the precise offset of internal files
  83.      * within the .phar, used with the {@link $_manifest} to load actual file contents
  84.      * @var array
  85.      */
  86.     private static $_pharMapping = array();
  87.     /**
  88.      * File listing for the .phar
  89.      * 
  90.      * The manifest is indexed per phar.
  91.      * 
  92.      * Files within the .phar are indexed by their relative path within the
  93.      * .phar.  Each file has this information in its internal array
  94.      *
  95.      * - 0 = uncompressed file size
  96.      * - 1 = timestamp of when file was added to phar
  97.      * - 2 = offset of file within phar relative to internal file's start
  98.      * - 3 = compressed file size (actual size in the phar)
  99.      * @var array
  100.      */
  101.     private static $_manifest = array();
  102.     /**
  103.      * Absolute offset of internal files within the .phar, indexed by absolute
  104.      * path to the .phar
  105.      *
  106.      * @var array
  107.      */
  108.     private static $_fileStart = array();
  109.     /**
  110.      * file name of the phar
  111.      *
  112.      * @var string
  113.      */
  114.     private $_basename;
  115.  
  116.     /**
  117.      * Map a full real file path to an alias used to refer to the .phar
  118.      *
  119.      * This function can only be called from the initialization of the .phar itself.
  120.      * Any attempt to call from outside the .phar or to re-alias the .phar will fail
  121.      * as a security measure.
  122.      * @param string $file full realpath() filepath, like /path/to/go-pear.phar
  123.      * @param string $alias alias used in opening a file within the phar
  124.      *                      like phar://go-pear.phar/file
  125.      * @param bool $compressed determines whether to attempt zlib uncompression
  126.      *                         on accessing internal files
  127.      * @param int $dataoffset the value of __COMPILER_HALT_OFFSET__
  128.      */
  129.     public static final function mapPhar($file, $dataoffset)
  130.     {
  131.         $file = realpath($file);
  132.         // this ensures that this is safe
  133.         if (!in_array($file, get_included_files())) {
  134.             die('SECURITY ERROR: PHP_Archive::mapPhar can only be called from within ' .
  135.                 'the phar that initiates it');
  136.         }
  137.         if (!is_array(self::$_pharMapping)) {
  138.             self::$_pharMapping = array();
  139.         }
  140.         if (!isset(self::$_manifest[$file])) {
  141.             $fp = fopen($file, 'rb');
  142.             // seek to __HALT_COMPILER_OFFSET__
  143.             fseek($fp, $dataoffset);
  144.             $manifest_length = unpack('Vlen', fread($fp, 4));
  145.             $manifest = '';
  146.             $last = '1';
  147.             while (strlen($last) && strlen($manifest) < $manifest_length['len']) {
  148.                 $read = 8192;
  149.                 if ($manifest_length['len'] - strlen($manifest) < 8192) {
  150.                     $read = $manifest_length['len'] - strlen($manifest);
  151.                 }
  152.                 $last = fread($fp, $read);
  153.                 $manifest .= $last;
  154.             }
  155.             if (strlen($manifest) < $manifest_length['len']) {
  156.                 die('ERROR: manifest length read was "' . strlen($manifest) .'" should be "' .
  157.                     $manifest_length['len'] . '"');
  158.             }
  159.             $info = self::_unserializeManifest($manifest);
  160.             if (!$info) {
  161.                 die; // error declared in unserializeManifest
  162.             }
  163.             $alias = $info['alias'];
  164.             self::$_manifest[$file] = $info['manifest'];
  165.             $compressed = $info['compressed'];
  166.             self::$_fileStart[$file] = ftell($fp);
  167.             fclose($fp);
  168.         }
  169.         if ($compressed) {
  170.             if (!function_exists('gzinflate')) {
  171.                 die('Error: zlib extension is not enabled - gzinflate() function needed' .
  172.                     ' for compressed .phars');
  173.             }
  174.         }
  175.         if (isset(self::$_pharMapping[$alias])) {
  176.             die('ERROR: PHP_Archive::mapPhar has already been called for alias "' .
  177.                 $alias . '" cannot re-alias to "' . $file . '"');
  178.         }
  179.         self::$_pharMapping[$alias] = array($file, $compressed, $dataoffset);
  180.     }
  181.  
  182.     /**
  183.      * @param string
  184.      */
  185.     private static function processFile($path)
  186.     {
  187.         if ($path == '.') {
  188.             return '';
  189.         }
  190.         $std = str_replace("\\", "/", $path);
  191.         while ($std != ($std = ereg_replace("[^\/:?]+/\.\./", "", $std))) ;
  192.         $std = str_replace("/./", "", $std);
  193.         if (strlen($std) > 1 && $std[0] == '/') {
  194.             $std = substr($std, 1);
  195.         }
  196.         if (strncmp($std, "./", 2) == 0) {
  197.             return substr($std, 2);
  198.         } else {
  199.             return $std;
  200.         }
  201.     }
  202.  
  203.     /**
  204.      * Seek in the master archive to a matching file or directory
  205.      * @param string
  206.      */
  207.     protected function selectFile($path, $allowdirs = true)
  208.     {
  209.         $std = self::processFile($path);
  210.         if (isset(self::$_manifest[$this->_archiveName][$path])) {
  211.             $this->_setCurrentFile($path);
  212.             return true;
  213.         }
  214.         if (!$allowdirs) {
  215.             return 'Error: "' . $path . '" is not a file in phar "' . $this->_basename . '"';
  216.         }
  217.         foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
  218.             if (empty($std) ||
  219.                   //$std is a directory
  220.                   strncmp($std.'/', $path, strlen($std)+1) == 0) {
  221.                 $this->currentFilename = $this->internalFileLength = $this->currentStat = null;
  222.                 return true;
  223.             }
  224.         }
  225.         return 'Error: "' . $path . '" not found in phar "' . $this->_basename . '"';
  226.     }
  227.  
  228.     private function _setCurrentFile($path)
  229.     {
  230.         $this->currentStat = array(
  231.             2 => 0100444, // file mode, readable by all, writeable by none
  232.             4 => 0, // uid
  233.             5 => 0, // gid
  234.             7 => self::$_manifest[$this->_archiveName][$path][0], // size
  235.             9 => self::$_manifest[$this->_archiveName][$path][1], // creation time
  236.             );
  237.         $this->currentFilename = $path;
  238.         $this->internalFileLength = self::$_manifest[$this->_archiveName][$path][2];
  239.         // seek to offset of file header within the .phar
  240.         if (is_resource(@$this->fp)) {
  241.             fseek($this->fp, self::$_fileStart[$this->_archiveName] + self::$_manifest[$this->_archiveName][$path][5]);
  242.         }
  243.     }
  244.  
  245.     /**
  246.      * Seek to a file within the master archive, and extract its contents
  247.      * @param string
  248.      * @return array|string an array containing an error message string is returned
  249.      *                      upon error, otherwise the file contents are returned
  250.      */
  251.     public function extractFile($path)
  252.     {
  253.         $this->fp = @fopen($this->_archiveName, "rb");
  254.         if (!$this->fp) {
  255.             return array('Error: cannot open phar "' . $this->_archiveName . '"');
  256.         }
  257.         if (($e = $this->selectFile($path, false)) === true) {
  258.             $data = '';
  259.             $count = $this->internalFileLength;
  260.             while ($count) {
  261.                 if ($count < 8192) {
  262.                     $data .= @fread($this->fp, $count);
  263.                     $count = 0;
  264.                 } else {
  265.                     $count -= 8192;
  266.                     $data .= @fread($this->fp, 8192);
  267.                 }
  268.             }
  269.             @fclose($this->fp);
  270.             if (self::$_manifest[$this->_archiveName][$path][4] & PHP_ARCHIVE_COMPRESSED) {
  271.                 $data = gzinflate($data);
  272.             }
  273.             if (!isset(self::$_manifest[$this->_archiveName][$path]['ok'])) {
  274.                 if (strlen($data) != $this->currentStat[7]) {
  275.                     return array("Not valid internal .phar file (size error {$size} != " .
  276.                         $this->currentStat[7] . ")");
  277.                 }
  278.                 if (self::$_manifest[$this->_archiveName][$path][3] != crc32($data)) {
  279.                     return array("Not valid internal .phar file (checksum error)");
  280.                 }
  281.                 self::$_manifest[$this->_archiveName][$path]['ok'] = true;
  282.             }
  283.             return $data;
  284.         } else {
  285.             @fclose($this->fp);
  286.             return array($e);
  287.         }
  288.     }
  289.  
  290.     /**
  291.      * Locate the .phar archive in the include_path and detect the file to open within
  292.      * the archive.
  293.      *
  294.      * Possible parameters are phar://filename_within_phar.ext or
  295.      * phar://pharname.phar/filename_within_phar.ext
  296.      *
  297.      * phar://filename_within_phar.ext will simply use the last .phar opened.
  298.      * @param string a file within the archive
  299.      * @return string the filename within the .phar to retrieve
  300.      */
  301.     public function initializeStream($file)
  302.     {
  303.         $info = parse_url($file);
  304.         if (!isset($info['host']) || !count(self::$_pharMapping)) {
  305.             // malformed internal file
  306.             return false;
  307.         }
  308.         if (!isset($info['path'])) {
  309.             // last opened phar is requested
  310.             $info['path'] = $info['host'];
  311.             $info['host'] = '';
  312.         } elseif (strlen($info['path']) > 1) {
  313.             $info['path'] = substr($info['path'], 1);
  314.         }
  315.         if (isset(self::$_pharMapping[$info['host']])) {
  316.             $this->_basename = $info['host'];
  317.             $this->_archiveName = self::$_pharMapping[$info['host']][0];
  318.             $this->_compressed = self::$_pharMapping[$info['host']][1];
  319.         } else {
  320.             // no such phar has been included, or last opened phar is requested
  321.             $pharinfo = end(self::$_pharMapping);
  322.             $this->_basename = key(self::$_pharMapping);
  323.             $this->_archiveName = $pharinfo[0];
  324.             $this->_compressed = $pharinfo[1];
  325.         }
  326.         $file = $info['path'];
  327.         return $file;
  328.     }
  329.  
  330.     /**
  331.      * extract the manifest into an internal array
  332.      *
  333.      * @param string $manifest
  334.      * @return false|array
  335.      */
  336.     private static function _unserializeManifest($manifest)
  337.     {
  338.         // retrieve the number of files in the manifest
  339.         $info = unpack('V', substr($manifest, 0, 4));
  340.         $apiver = substr($manifest, 4, 2);
  341.         $apiver = bin2hex($apiver);
  342.         $apiver_dots = hexdec($apiver[0]) . '.' . hexdec($apiver[1]) . '.' . hexdec($apiver[2]);
  343.         $majorcompat = hexdec($apiver[0]);
  344.         $calcapi = explode('.', '0.8.0');
  345.         if ($calcapi[0] != $majorcompat) {
  346.             trigger_error('Phar is incompatible API version ' . $apiver_dots . ', but ' .
  347.                 'PHP_Archive is API version 0.8.0');
  348.             return false;
  349.         }
  350.         if ($calcapi[0] === '0') {
  351.             if ('0.8.0' != $apiver_dots) {
  352.                 trigger_error('Phar is API version ' . $apiver_dots .
  353.                     ', but PHP_Archive is API version 0.8.0', E_USER_ERROR);
  354.                 return false;
  355.             }
  356.         }
  357.         $ret = array('compressed' => $apiver[3]);
  358.         $aliaslen = unpack('V', substr($manifest, 6, 4));
  359.         $ret['alias'] = substr($manifest, 10, $aliaslen[1]);
  360.         $manifest = substr($manifest, 10 + $aliaslen[1]);
  361.         $offset = 0;
  362.         $start = 0;
  363.         for ($i = 0; $i < $info[1]; $i++) {
  364.             // length of the file name
  365.             $len = unpack('V', substr($manifest, $start, 4));
  366.             $start += 4;
  367.             // file name
  368.             $savepath = substr($manifest, $start, $len[1]);
  369.             $start += $len[1];
  370.             // retrieve manifest data:
  371.             // 0 = uncompressed file size
  372.             // 1 = timestamp of when file was added to phar
  373.             // 2 = compressed filesize
  374.             // 3 = crc32
  375.             // 4 = flags
  376.             $ret['manifest'][$savepath] = array_values(unpack('Va/Vb/Vc/Vd/Ce', substr($manifest, $start, 17)));
  377.             $ret['manifest'][$savepath][5] = $offset;
  378.             $offset += $ret['manifest'][$savepath][2];
  379.             $start += 17;
  380.         }
  381.         return $ret;
  382.     }
  383.  
  384.     /**
  385.      * Open the requested file - PHP streams API
  386.      *
  387.      * @param string $file String provided by the Stream wrapper
  388.      * @access private
  389.      */
  390.     public function stream_open($file)
  391.     {
  392.         return $this->_streamOpen($file);
  393.     }
  394.  
  395.     /**
  396.      * @param string filename to opne, or directory name
  397.      * @param bool if true, a directory will be matched, otherwise only files
  398.      *             will be matched
  399.      * @uses trigger_error()
  400.      * @return bool success of opening
  401.      * @access private
  402.      */
  403.     private function _streamOpen($file, $searchForDir = false)
  404.     {
  405.         $path = $this->initializeStream($file);
  406.         if (!$path) {
  407.             trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
  408.         }
  409.         if (is_array($this->file = $this->extractFile($path))) {
  410.             trigger_error($this->file[0], E_USER_ERROR);
  411.             return false;
  412.         }
  413.         if ($path != $this->currentFilename) {
  414.             if (!$searchForDir) {
  415.                 trigger_error("Cannot open '$file', is a directory", E_USER_ERROR);
  416.                 return false;
  417.             } else {
  418.                 $this->file = '';
  419.                 return true;
  420.             }
  421.         }
  422.  
  423.         if (!is_null($this->file) && $this->file !== false) {
  424.             return true;
  425.         } else {
  426.             return false;
  427.         }
  428.     }
  429.     
  430.     /**
  431.      * Read the data - PHP streams API
  432.      *
  433.      * @param int
  434.      * @access private
  435.      */
  436.     public function stream_read($count)
  437.     {
  438.         $ret = substr($this->file, $this->position, $count);
  439.         $this->position += strlen($ret);
  440.         return $ret;
  441.     }
  442.     
  443.     /**
  444.      * Whether we've hit the end of the file - PHP streams API
  445.      * @access private
  446.      */
  447.     function stream_eof()
  448.     {
  449.         return $this->position >= $this->currentStat[7];
  450.     }
  451.     
  452.     /**
  453.      * For seeking the stream - PHP streams API
  454.      * @param int
  455.      * @param SEEK_SET|SEEK_CUR|SEEK_END
  456.      * @access private
  457.      */
  458.     public function stream_seek($pos, $whence)
  459.     {
  460.         switch ($whence) {
  461.             case SEEK_SET:
  462.                 if ($pos < 0) {
  463.                     return false;
  464.                 }
  465.                 $this->position = $pos;
  466.                 break;
  467.             case SEEK_CUR:
  468.                 if ($pos + $this->currentStat[7] < 0) {
  469.                     return false;
  470.                 }
  471.                 $this->position += $pos;
  472.                 break;
  473.             case SEEK_END:
  474.                 if ($pos + $this->currentStat[7] < 0) {
  475.                     return false;
  476.                 }
  477.                 $this->position = $pos + $this->currentStat[7];
  478.             default:
  479.                 return false;
  480.         }
  481.         return true;
  482.     }
  483.     
  484.     /**
  485.      * The current position in the stream - PHP streams API
  486.      * @access private
  487.      */
  488.     public function stream_tell()
  489.     {
  490.         return $this->position;
  491.     }
  492.  
  493.     /**
  494.      * The result of an fstat call, returns mod time from creation, and file size -
  495.      * PHP streams API
  496.      * @uses _stream_stat()
  497.      * @access private
  498.      */
  499.     public function stream_stat()
  500.     {
  501.         return $this->_stream_stat();
  502.     }
  503.  
  504.     /**
  505.      * Retrieve statistics on a file or directory within the .phar
  506.      * @param string file/directory to stat
  507.      * @access private
  508.      */
  509.     public function _stream_stat($file = null)
  510.     {
  511.         $std = $file ? self::processFile($file) : $this->currentFilename;
  512.         if ($file) {
  513.             if (isset(self::$_manifest[$this->_archiveName][$file])) {
  514.                 $this->_setCurrentFile($file);
  515.                 $isdir = false;
  516.             } else {
  517.                 $isdir = true;
  518.             }
  519.         } else {
  520.             $isdir = false; // open streams must be files
  521.         }
  522.         $mode = $isdir ? 0040444 : 0100444;
  523.         // 040000 = dir, 010000 = file
  524.         // everything is readable, nothing is writeable
  525.         return array(
  526.            0, 0, $mode, 0, 0, 0, 0, 0, 0, 0, 0, 0, // non-associative indices
  527.            'dev' => 0, 'ino' => 0,
  528.            'mode' => $mode,
  529.            'nlink' => 0, 'uid' => 0, 'gid' => 0, 'rdev' => 0, 'blksize' => 0, 'blocks' => 0,
  530.            'size' => $this->currentStat[7],
  531.            'atime' => $this->currentStat[9],
  532.            'mtime' => $this->currentStat[9],
  533.            'ctime' => $this->currentStat[9],
  534.            );
  535.     }
  536.  
  537.     /**
  538.      * Stat a closed file or directory - PHP streams API
  539.      * @param string
  540.      * @param int
  541.      * @access private
  542.      */
  543.     public function url_stat($url, $flags)
  544.     {
  545.         $path = $this->initializeStream($url);
  546.         return $this->_stream_stat($path);
  547.     }
  548.  
  549.     /**
  550.      * Open a directory in the .phar for reading - PHP streams API
  551.      * @param string directory name
  552.      * @access private
  553.      */
  554.     public function dir_opendir($path)
  555.     {
  556.         $info = parse_url($path);
  557.         $path = !empty($info['path']) ?
  558.             $info['host'] . $info['path'] : $info['host'] . '/';
  559.         $path = $this->initializeStream('phar://' . $path);
  560.         if (isset(self::$_manifest[$this->_archiveName][$path])) {
  561.             trigger_error('Error: "' . $path . '" is a file, and cannot be opened with opendir',
  562.                 E_USER_ERROR);
  563.             return false;
  564.         }
  565.         if ($path == false) {
  566.             trigger_error('Error: Unknown phar in "' . $file . '"', E_USER_ERROR);
  567.             return false;
  568.         }
  569.         $this->fp = @fopen($this->_archiveName, "rb");
  570.         if (!$this->fp) {
  571.             trigger_error('Error: cannot open phar "' . $this->_archiveName . '"');
  572.             return false;
  573.         }
  574.         $this->_dirFiles = array();
  575.         foreach (self::$_manifest[$this->_archiveName] as $file => $info) {
  576.             if ($path == '/') {
  577.                 if (strpos($file, '/')) {
  578.                     $a = explode('/', $file);
  579.                     $this->_dirFiles[array_shift($a)] = true;
  580.                 } else {
  581.                     $this->_dirFiles[$file] = true;
  582.                 }
  583.             } elseif (strpos($file, $path) === 0) {
  584.                 $fname = substr($file, strlen($path) + 1);
  585.                 if (strpos($fname, '/')) {
  586.                     $a = explode('/', $fname);
  587.                     $this->_dirFiles[array_shift($a)] = true;
  588.                 } elseif (strlen($file) != strlen($path)) {
  589.                     // if the two match exactly, the path searched for was
  590.                     // not a directory, but was a file.
  591.                     $this->_dirFiles[$fname] = true;
  592.                 }
  593.             }
  594.         }
  595.         @fclose($this->fp);
  596.         @uksort($this->_dirFiles, 'strnatcmp');
  597.         return true;
  598.     }
  599.  
  600.     /**
  601.      * Read the next directory entry - PHP streams API
  602.      * @access private
  603.      */
  604.     public function dir_readdir()
  605.     {
  606.         $ret = key($this->_dirFiles);
  607.         @next($this->_dirFiles);
  608.         if (!$ret) {
  609.             return false;
  610.         }
  611.         return $ret;
  612.     }
  613.  
  614.     /**
  615.      * Close a directory handle opened with opendir() - PHP streams API
  616.      * @access private
  617.      */
  618.     public function dir_closedir()
  619.     {
  620.         $this->_dirFiles = array();
  621.         reset($this->_dirFiles);
  622.         return true;
  623.     }
  624.  
  625.     /**
  626.      * Rewind to the first directory entry - PHP streams API
  627.      * @access private
  628.      */
  629.     public function dir_rewinddir()
  630.     {
  631.         reset($this->_dirFiles);
  632.         return true;
  633.     }
  634.  
  635.     /**
  636.      * API version of this class
  637.      * @return string
  638.      */
  639.     public final function APIVersion()
  640.     {
  641.         return '0.8.0';
  642.     }
  643. }}
  644. if (!class_exists('Phar')) {
  645.     if (!in_array('phar', stream_get_wrappers())) {
  646.         stream_wrapper_register('phar', 'PHP_Archive');
  647.     }
  648.     PHP_Archive::mapPhar(__FILE__, __COMPILER_HALT_OFFSET__);
  649. } else {
  650.     Phar::mapPhar();
  651. }
  652. if (class_exists('PHP_Archive') && !in_array('phar', stream_get_wrappers())) {
  653.     stream_wrapper_register('phar', 'PHP_Archive');
  654. }
  655. @ini_set('memory_limit', -1);
  656.  
  657. require_once 'phar://go-pear.phar/index.php';
  658. __HALT_COMPILER();! @ go-pear.pharArchive/Tar.phpdεx╣FEdεEyNConsole/Getopt.phpK&x╣FEK&ö^æe    index.phpÉx╣FEÉù╖≈ OS/Guess.php},x╣FE},ë╟¬αPEAR.phpiïx╣FEiïS*AePEAR/ChannelFile.php3µx╣FE3µ═xíPEAR/ChannelFile/Parser.php╠x╣FE╠Öf¬PEAR/Command.php5x╣FE57╒╞PEAR/Command/Common.php$x╣FE$█ àPEAR/Command/Install.php╨▒x╣FE╨▒áìÖ~PEAR/Command/Install.xmläx╣FEäó├┤PEAR/Common.phpPÉx╣FEPÉ?╟°▄PEAR/Config.php╩x╣FE╩2'môPEAR/Dependency2.php¥┬x╣FE¥┬╓n┤PEAR/DependencyDB.php7ex╣FE7e4▀ΓöPEAR/Downloader.php7x╣FE7┐=ùaPEAR/Downloader/Package.php░#x╣FE░#┴╨*ÆPEAR/ErrorStack.phpÆêx╣FEÆê╪⌡πδPEAR/Frontend.phpéx╣FEé≡t#ΩPEAR/Frontend/CLI.php╖px╣FE╖p╫#0╩+PEAR/go-pear-tarballs/Archive_Tar-1.3.1.tarPx╣FEPip╠+,PEAR/go-pear-tarballs/Console_Getopt-1.2.tar6x╣FE6ªΩhG%PEAR/go-pear-tarballs/PEAR-1.4.11.tarªx╣FEª3ÆWPEAR/Installer.phpÉx╣FEɰlPEAR/Installer/Role.phpà!x╣FEà!╩,PEAR/Installer/Role/Common.php┤x╣FE┤G╥▌9PEAR/Installer/Role/Data.php▌x╣FE▌3D@PEAR/Installer/Role/Data.xmláx╣FEá╩⌐PEAR/Installer/Role/Doc.php┌x╣FE┌ÜÖSPEAR/Installer/Role/Doc.xmlƒx╣FEƒ_5ε╤PEAR/Installer/Role/Php.php┌x╣FE┌╚uwPEAR/Installer/Role/Php.xml╗x╣FE╗ΘÇ!ΦPEAR/Installer/Role/Script.phpπx╣FEπNu[kPEAR/Installer/Role/Script.xml╛x╣FE╛╨T─PEAR/Installer/Role/Test.php▌x╣FE▌+≥~\PEAR/Installer/Role/Test.xmláx╣FEá▀┴╗aPEAR/PackageFile.php+Cx╣FE+C Ωÿs!PEAR/PackageFile/Generator/v1.phpî╦x╣FEî╦ü┼╓║!PEAR/PackageFile/Generator/v2.php⌠x╣FE⌠*ÇIgPEAR/PackageFile/Parser/v1.phpïCx╣FEïC █n╧PEAR/PackageFile/Parser/v2.php x╣FE º │PEAR/PackageFile/v1.phpÿ╦x╣FEÿ╦2rGbPEAR/PackageFile/v2.phpºx╣FEº Φä■PEAR/PackageFile/v2/rw.php╠²x╣FE╠²«òuF!PEAR/PackageFile/v2/Validator.phpjKx╣FEjK╗êEBPEAR/Registry.php=&x╣FE=&B≤üRPEAR/Remote.phpÇIx╣FEÇI▄¢Ö
  659. PEAR/REST.phpα;x╣FEα;ÜpwmPEAR/REST/10.phpSmx╣FESm╢Θó└PEAR/Start.php╦4x╣FE╦49╔à└PEAR/Start/CLI.phpTx╣FET╣]½┌PEAR/Task/Common.php)x╣FE)∙uÅ PEAR/Task/Postinstallscript.php;x╣FE;;7¿í"PEAR/Task/Postinstallscript/rw.php
  660. x╣FE
  661. ╒≥╓RPEAR/Task/Replace.php╬x╣FE╬U⌐û¬PEAR/Task/Replace/rw.php x╣FE π∞    3PEAR/Task/Unixeol.php▒
  662. x╣FE▒
  663. ╨@┌ôPEAR/Task/Unixeol/rw.phpx╣FEF£'vPEAR/Task/Windowseol.php¡
  664. x╣FE¡
  665. ºPEAR/Task/Windowseol/rw.php,x╣FE,r|┬QPEAR/Validate.phpµYx╣FEµY╔α"'PEAR/Validator/PECL.php╩x╣FE╩o    τ(PEAR/XMLParser.phpjx╣FEjnτ╬v
  666. System.php²Nx╣FE²N^ûú<?php
  667. /* vim: set ts=4 sw=4: */
  668. // +----------------------------------------------------------------------+
  669. // | PHP Version 4                                                        |
  670. // +----------------------------------------------------------------------+
  671. // | Copyright (c) 1997-2003 The PHP Group                                |
  672. // +----------------------------------------------------------------------+
  673. // | This source file is subject to version 3.0 of the PHP license,       |
  674. // | that is bundled with this package in the file LICENSE, and is        |
  675. // | available through the world-wide-web at the following url:           |
  676. // | http://www.php.net/license/3_0.txt.                                  |
  677. // | If you did not receive a copy of the PHP license and are unable to   |
  678. // | obtain it through the world-wide-web, please send a note to          |
  679. // | license@php.net so we can mail you a copy immediately.               |
  680. // +----------------------------------------------------------------------+
  681. // | Author: Vincent Blavet <vincent@phpconcept.net>                      |
  682. // +----------------------------------------------------------------------+
  683. //
  684. // $Id: Tar.php,v 1.23 2006/05/12 02:38:58 cellog Exp $
  685.  
  686. require_once 'phar://go-pear.phar/PEAR.php';
  687.  
  688.  
  689. define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
  690.  
  691. /**
  692. * Creates a (compressed) Tar archive
  693. *
  694. * @author   Vincent Blavet <vincent@phpconcept.net>
  695. * @version  $Revision: 1.23 $
  696. * @package  Archive
  697. */
  698. class Archive_Tar extends PEAR
  699. {
  700.     /**
  701.     * @var string Name of the Tar
  702.     */
  703.     var $_tarname='';
  704.  
  705.     /**
  706.     * @var boolean if true, the Tar file will be gzipped
  707.     */
  708.     var $_compress=false;
  709.  
  710.     /**
  711.     * @var string Type of compression : 'none', 'gz' or 'bz2'
  712.     */
  713.     var $_compress_type='none';
  714.  
  715.     /**
  716.     * @var string Explode separator
  717.     */
  718.     var $_separator=' ';
  719.  
  720.     /**
  721.     * @var file descriptor
  722.     */
  723.     var $_file=0;
  724.  
  725.     /**
  726.     * @var string Local Tar name of a remote Tar (http:// or ftp://)
  727.     */
  728.     var $_temp_tarname='';
  729.  
  730.     // {{{ constructor
  731.     /**
  732.     * Archive_Tar Class constructor. This flavour of the constructor only
  733.     * declare a new Archive_Tar object, identifying it by the name of the
  734.     * tar file.
  735.     * If the compress argument is set the tar will be read or created as a
  736.     * gzip or bz2 compressed TAR file.
  737.     *
  738.     * @param    string  $p_tarname  The name of the tar archive to create
  739.     * @param    string  $p_compress can be null, 'gz' or 'bz2'. This
  740.     *                   parameter indicates if gzip or bz2 compression
  741.     *                   is required.  For compatibility reason the
  742.     *                   boolean value 'true' means 'gz'.
  743.     * @access public
  744.     */
  745.     function Archive_Tar($p_tarname, $p_compress = null)
  746.     {
  747.         $this->PEAR();
  748.         $this->_compress = false;
  749.         $this->_compress_type = 'none';
  750.         if (($p_compress === null) || ($p_compress == '')) {
  751.             if (@file_exists($p_tarname)) {
  752.                 if ($fp = @fopen($p_tarname, "rb")) {
  753.                     // look for gzip magic cookie
  754.                     $data = fread($fp, 2);
  755.                     fclose($fp);
  756.                     if ($data == "\37\213") {
  757.                         $this->_compress = true;
  758.                         $this->_compress_type = 'gz';
  759.                     // No sure it's enought for a magic code ....
  760.                     } elseif ($data == "BZ") {
  761.                         $this->_compress = true;
  762.                         $this->_compress_type = 'bz2';
  763.                     }
  764.                 }
  765.             } else {
  766.                 // probably a remote file or some file accessible
  767.                 // through a stream interface
  768.                 if (substr($p_tarname, -2) == 'gz') {
  769.                     $this->_compress = true;
  770.                     $this->_compress_type = 'gz';
  771.                 } elseif ((substr($p_tarname, -3) == 'bz2') ||
  772.                           (substr($p_tarname, -2) == 'bz')) {
  773.                     $this->_compress = true;
  774.                     $this->_compress_type = 'bz2';
  775.                 }
  776.             }
  777.         } else {
  778.             if (($p_compress === true) || ($p_compress == 'gz')) {
  779.                 $this->_compress = true;
  780.                 $this->_compress_type = 'gz';
  781.             } else if ($p_compress == 'bz2') {
  782.                 $this->_compress = true;
  783.                 $this->_compress_type = 'bz2';
  784.             } else {
  785.                 die("Unsupported compression type '$p_compress'\n".
  786.                     "Supported types are 'gz' and 'bz2'.\n");
  787.                 return false;
  788.             }
  789.         }
  790.         $this->_tarname = $p_tarname;
  791.         if ($this->_compress) { // assert zlib or bz2 extension support
  792.             if ($this->_compress_type == 'gz')
  793.                 $extname = 'zlib';
  794.             else if ($this->_compress_type == 'bz2')
  795.                 $extname = 'bz2';
  796.  
  797.             if (!extension_loaded($extname)) {
  798.                 PEAR::loadExtension($extname);
  799.             }
  800.             if (!extension_loaded($extname)) {
  801.                 die("The extension '$extname' couldn't be found.\n".
  802.                     "Please make sure your version of PHP was built ".
  803.                     "with '$extname' support.\n");
  804.                 return false;
  805.             }
  806.         }
  807.     }
  808.     // }}}
  809.  
  810.     // {{{ destructor
  811.     function _Archive_Tar()
  812.     {
  813.         $this->_close();
  814.         // ----- Look for a local copy to delete
  815.         if ($this->_temp_tarname != '')
  816.             @unlink($this->_temp_tarname);
  817.         $this->_PEAR();
  818.     }
  819.     // }}}
  820.  
  821.     // {{{ create()
  822.     /**
  823.     * This method creates the archive file and add the files / directories
  824.     * that are listed in $p_filelist.
  825.     * If a file with the same name exist and is writable, it is replaced
  826.     * by the new tar.
  827.     * The method return false and a PEAR error text.
  828.     * The $p_filelist parameter can be an array of string, each string
  829.     * representing a filename or a directory name with their path if
  830.     * needed. It can also be a single string with names separated by a
  831.     * single blank.
  832.     * For each directory added in the archive, the files and
  833.     * sub-directories are also added.
  834.     * See also createModify() method for more details.
  835.     *
  836.     * @param array  $p_filelist An array of filenames and directory names, or a
  837.     *                           single string with names separated by a single
  838.     *                           blank space.
  839.     * @return                   true on success, false on error.
  840.     * @see createModify()
  841.     * @access public
  842.     */
  843.     function create($p_filelist)
  844.     {
  845.         return $this->createModify($p_filelist, '', '');
  846.     }
  847.     // }}}
  848.  
  849.     // {{{ add()
  850.     /**
  851.     * This method add the files / directories that are listed in $p_filelist in
  852.     * the archive. If the archive does not exist it is created.
  853.     * The method return false and a PEAR error text.
  854.     * The files and directories listed are only added at the end of the archive,
  855.     * even if a file with the same name is already archived.
  856.     * See also createModify() method for more details.
  857.     *
  858.     * @param array  $p_filelist An array of filenames and directory names, or a
  859.     *                           single string with names separated by a single
  860.     *                           blank space.
  861.     * @return                   true on success, false on error.
  862.     * @see createModify()
  863.     * @access public
  864.     */
  865.     function add($p_filelist)
  866.     {
  867.         return $this->addModify($p_filelist, '', '');
  868.     }
  869.     // }}}
  870.  
  871.     // {{{ extract()
  872.     function extract($p_path='')
  873.     {
  874.         return $this->extractModify($p_path, '');
  875.     }
  876.     // }}}
  877.  
  878.     // {{{ listContent()
  879.     function listContent()
  880.     {
  881.         $v_list_detail = array();
  882.  
  883.         if ($this->_openRead()) {
  884.             if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
  885.                 unset($v_list_detail);
  886.                 $v_list_detail = 0;
  887.             }
  888.             $this->_close();
  889.         }
  890.  
  891.         return $v_list_detail;
  892.     }
  893.     // }}}
  894.  
  895.     // {{{ createModify()
  896.     /**
  897.     * This method creates the archive file and add the files / directories
  898.     * that are listed in $p_filelist.
  899.     * If the file already exists and is writable, it is replaced by the
  900.     * new tar. It is a create and not an add. If the file exists and is
  901.     * read-only or is a directory it is not replaced. The method return
  902.     * false and a PEAR error text.
  903.     * The $p_filelist parameter can be an array of string, each string
  904.     * representing a filename or a directory name with their path if
  905.     * needed. It can also be a single string with names separated by a
  906.     * single blank.
  907.     * The path indicated in $p_remove_dir will be removed from the
  908.     * memorized path of each file / directory listed when this path
  909.     * exists. By default nothing is removed (empty path '')
  910.     * The path indicated in $p_add_dir will be added at the beginning of
  911.     * the memorized path of each file / directory listed. However it can
  912.     * be set to empty ''. The adding of a path is done after the removing
  913.     * of path.
  914.     * The path add/remove ability enables the user to prepare an archive
  915.     * for extraction in a different path than the origin files are.
  916.     * See also addModify() method for file adding properties.
  917.     *
  918.     * @param array  $p_filelist     An array of filenames and directory names,
  919.     *                               or a single string with names separated by
  920.     *                               a single blank space.
  921.     * @param string $p_add_dir      A string which contains a path to be added
  922.     *                               to the memorized path of each element in
  923.     *                               the list.
  924.     * @param string $p_remove_dir   A string which contains a path to be
  925.     *                               removed from the memorized path of each
  926.     *                               element in the list, when relevant.
  927.     * @return boolean               true on success, false on error.
  928.     * @access public
  929.     * @see addModify()
  930.     */
  931.     function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
  932.     {
  933.         $v_result = true;
  934.  
  935.         if (!$this->_openWrite())
  936.             return false;
  937.  
  938.         if ($p_filelist != '') {
  939.             if (is_array($p_filelist))
  940.                 $v_list = $p_filelist;
  941.             elseif (is_string($p_filelist))
  942.                 $v_list = explode($this->_separator, $p_filelist);
  943.             else {
  944.                 $this->_cleanFile();
  945.                 $this->_error('Invalid file list');
  946.                 return false;
  947.             }
  948.  
  949.             $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
  950.         }
  951.  
  952.         if ($v_result) {
  953.             $this->_writeFooter();
  954.             $this->_close();
  955.         } else
  956.             $this->_cleanFile();
  957.  
  958.         return $v_result;
  959.     }
  960.     // }}}
  961.  
  962.     // {{{ addModify()
  963.     /**
  964.     * This method add the files / directories listed in $p_filelist at the
  965.     * end of the existing archive. If the archive does not yet exists it
  966.     * is created.
  967.     * The $p_filelist parameter can be an array of string, each string
  968.     * representing a filename or a directory name with their path if
  969.     * needed. It can also be a single string with names separated by a
  970.     * single blank.
  971.     * The path indicated in $p_remove_dir will be removed from the
  972.     * memorized path of each file / directory listed when this path
  973.     * exists. By default nothing is removed (empty path '')
  974.     * The path indicated in $p_add_dir will be added at the beginning of
  975.     * the memorized path of each file / directory listed. However it can
  976.     * be set to empty ''. The adding of a path is done after the removing
  977.     * of path.
  978.     * The path add/remove ability enables the user to prepare an archive
  979.     * for extraction in a different path than the origin files are.
  980.     * If a file/dir is already in the archive it will only be added at the
  981.     * end of the archive. There is no update of the existing archived
  982.     * file/dir. However while extracting the archive, the last file will
  983.     * replace the first one. This results in a none optimization of the
  984.     * archive size.
  985.     * If a file/dir does not exist the file/dir is ignored. However an
  986.     * error text is send to PEAR error.
  987.     * If a file/dir is not readable the file/dir is ignored. However an
  988.     * error text is send to PEAR error.
  989.     *
  990.     * @param array      $p_filelist     An array of filenames and directory
  991.     *                                   names, or a single string with names
  992.     *                                   separated by a single blank space.
  993.     * @param string     $p_add_dir      A string which contains a path to be
  994.     *                                   added to the memorized path of each
  995.     *                                   element in the list.
  996.     * @param string     $p_remove_dir   A string which contains a path to be
  997.     *                                   removed from the memorized path of
  998.     *                                   each element in the list, when
  999.     *                                   relevant.
  1000.     * @return                           true on success, false on error.
  1001.     * @access public
  1002.     */
  1003.     function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
  1004.     {
  1005.         $v_result = true;
  1006.  
  1007.         if (!$this->_isArchive())
  1008.             $v_result = $this->createModify($p_filelist, $p_add_dir,
  1009.                                             $p_remove_dir);
  1010.         else {
  1011.             if (is_array($p_filelist))
  1012.                 $v_list = $p_filelist;
  1013.             elseif (is_string($p_filelist))
  1014.                 $v_list = explode($this->_separator, $p_filelist);
  1015.             else {
  1016.                 $this->_error('Invalid file list');
  1017.                 return false;
  1018.             }
  1019.  
  1020.             $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
  1021.         }
  1022.  
  1023.         return $v_result;
  1024.     }
  1025.     // }}}
  1026.  
  1027.     // {{{ addString()
  1028.     /**
  1029.     * This method add a single string as a file at the
  1030.     * end of the existing archive. If the archive does not yet exists it
  1031.     * is created.
  1032.     *
  1033.     * @param string     $p_filename     A string which contains the full
  1034.     *                                   filename path that will be associated
  1035.     *                                   with the string.
  1036.     * @param string     $p_string       The content of the file added in
  1037.     *                                   the archive.
  1038.     * @return                           true on success, false on error.
  1039.     * @access public
  1040.     */
  1041.     function addString($p_filename, $p_string)
  1042.     {
  1043.         $v_result = true;
  1044.         
  1045.         if (!$this->_isArchive()) {
  1046.             if (!$this->_openWrite()) {
  1047.                 return false;
  1048.             }
  1049.             $this->_close();
  1050.         }
  1051.         
  1052.         if (!$this->_openAppend())
  1053.             return false;
  1054.  
  1055.         // Need to check the get back to the temporary file ? ....
  1056.         $v_result = $this->_addString($p_filename, $p_string);
  1057.  
  1058.         $this->_writeFooter();
  1059.  
  1060.         $this->_close();
  1061.  
  1062.         return $v_result;
  1063.     }
  1064.     // }}}
  1065.  
  1066.     // {{{ extractModify()
  1067.     /**
  1068.     * This method extract all the content of the archive in the directory
  1069.     * indicated by $p_path. When relevant the memorized path of the
  1070.     * files/dir can be modified by removing the $p_remove_path path at the
  1071.     * beginning of the file/dir path.
  1072.     * While extracting a file, if the directory path does not exists it is
  1073.     * created.
  1074.     * While extracting a file, if the file already exists it is replaced
  1075.     * without looking for last modification date.
  1076.     * While extracting a file, if the file already exists and is write
  1077.     * protected, the extraction is aborted.
  1078.     * While extracting a file, if a directory with the same name already
  1079.     * exists, the extraction is aborted.
  1080.     * While extracting a directory, if a file with the same name already
  1081.     * exists, the extraction is aborted.
  1082.     * While extracting a file/directory if the destination directory exist
  1083.     * and is write protected, or does not exist but can not be created,
  1084.     * the extraction is aborted.
  1085.     * If after extraction an extracted file does not show the correct
  1086.     * stored file size, the extraction is aborted.
  1087.     * When the extraction is aborted, a PEAR error text is set and false
  1088.     * is returned. However the result can be a partial extraction that may
  1089.     * need to be manually cleaned.
  1090.     *
  1091.     * @param string $p_path         The path of the directory where the
  1092.     *                               files/dir need to by extracted.
  1093.     * @param string $p_remove_path  Part of the memorized path that can be
  1094.     *                               removed if present at the beginning of
  1095.     *                               the file/dir path.
  1096.     * @return boolean               true on success, false on error.
  1097.     * @access public
  1098.     * @see extractList()
  1099.     */
  1100.     function extractModify($p_path, $p_remove_path)
  1101.     {
  1102.         $v_result = true;
  1103.         $v_list_detail = array();
  1104.  
  1105.         if ($v_result = $this->_openRead()) {
  1106.             $v_result = $this->_extractList($p_path, $v_list_detail,
  1107.                                             "complete", 0, $p_remove_path);
  1108.             $this->_close();
  1109.         }
  1110.  
  1111.         return $v_result;
  1112.     }
  1113.     // }}}
  1114.  
  1115.     // {{{ extractInString()
  1116.     /**
  1117.     * This method extract from the archive one file identified by $p_filename.
  1118.     * The return value is a string with the file content, or NULL on error.
  1119.     * @param string $p_filename     The path of the file to extract in a string.
  1120.     * @return                       a string with the file content or NULL.
  1121.     * @access public
  1122.     */
  1123.     function extractInString($p_filename)
  1124.     {
  1125.         if ($this->_openRead()) {
  1126.             $v_result = $this->_extractInString($p_filename);
  1127.             $this->_close();
  1128.         } else {
  1129.             $v_result = NULL;
  1130.         }
  1131.  
  1132.         return $v_result;
  1133.     }
  1134.     // }}}
  1135.  
  1136.     // {{{ extractList()
  1137.     /**
  1138.     * This method extract from the archive only the files indicated in the
  1139.     * $p_filelist. These files are extracted in the current directory or
  1140.     * in the directory indicated by the optional $p_path parameter.
  1141.     * If indicated the $p_remove_path can be used in the same way as it is
  1142.     * used in extractModify() method.
  1143.     * @param array  $p_filelist     An array of filenames and directory names,
  1144.     *                               or a single string with names separated
  1145.     *                               by a single blank space.
  1146.     * @param string $p_path         The path of the directory where the
  1147.     *                               files/dir need to by extracted.
  1148.     * @param string $p_remove_path  Part of the memorized path that can be
  1149.     *                               removed if present at the beginning of
  1150.     *                               the file/dir path.
  1151.     * @return                       true on success, false on error.
  1152.     * @access public
  1153.     * @see extractModify()
  1154.     */
  1155.     function extractList($p_filelist, $p_path='', $p_remove_path='')
  1156.     {
  1157.         $v_result = true;
  1158.         $v_list_detail = array();
  1159.  
  1160.         if (is_array($p_filelist))
  1161.             $v_list = $p_filelist;
  1162.         elseif (is_string($p_filelist))
  1163.             $v_list = explode($this->_separator, $p_filelist);
  1164.         else {
  1165.             $this->_error('Invalid string list');
  1166.             return false;
  1167.         }
  1168.  
  1169.         if ($v_result = $this->_openRead()) {
  1170.             $v_result = $this->_extractList($p_path, $v_list_detail, "partial",
  1171.                                             $v_list, $p_remove_path);
  1172.             $this->_close();
  1173.         }
  1174.  
  1175.         return $v_result;
  1176.     }
  1177.     // }}}
  1178.  
  1179.     // {{{ setAttribute()
  1180.     /**
  1181.     * This method set specific attributes of the archive. It uses a variable
  1182.     * list of parameters, in the format attribute code + attribute values :
  1183.     * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
  1184.     * @param mixed $argv            variable list of attributes and values
  1185.     * @return                       true on success, false on error.
  1186.     * @access public
  1187.     */
  1188.     function setAttribute()
  1189.     {
  1190.         $v_result = true;
  1191.         
  1192.         // ----- Get the number of variable list of arguments
  1193.         if (($v_size = func_num_args()) == 0) {
  1194.             return true;
  1195.         }
  1196.         
  1197.         // ----- Get the arguments
  1198.         $v_att_list = &func_get_args();
  1199.  
  1200.         // ----- Read the attributes
  1201.         $i=0;
  1202.         while ($i<$v_size) {
  1203.  
  1204.             // ----- Look for next option
  1205.             switch ($v_att_list[$i]) {
  1206.                 // ----- Look for options that request a string value
  1207.                 case ARCHIVE_TAR_ATT_SEPARATOR :
  1208.                     // ----- Check the number of parameters
  1209.                     if (($i+1) >= $v_size) {
  1210.                         $this->_error('Invalid number of parameters for '
  1211.                                       .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
  1212.                         return false;
  1213.                     }
  1214.  
  1215.                     // ----- Get the value
  1216.                     $this->_separator = $v_att_list[$i+1];
  1217.                     $i++;
  1218.                 break;
  1219.  
  1220.                 default :
  1221.                     $this->_error('Unknow attribute code '.$v_att_list[$i].'');
  1222.                     return false;
  1223.             }
  1224.  
  1225.             // ----- Next attribute
  1226.             $i++;
  1227.         }
  1228.  
  1229.         return $v_result;
  1230.     }
  1231.     // }}}
  1232.  
  1233.     // {{{ _error()
  1234.     function _error($p_message)
  1235.     {
  1236.         // ----- To be completed
  1237.         $this->raiseError($p_message);
  1238.     }
  1239.     // }}}
  1240.  
  1241.     // {{{ _warning()
  1242.     function _warning($p_message)
  1243.     {
  1244.         // ----- To be completed
  1245.         $this->raiseError($p_message);
  1246.     }
  1247.     // }}}
  1248.  
  1249.     // {{{ _isArchive()
  1250.     function _isArchive($p_filename=NULL)
  1251.     {
  1252.         if ($p_filename == NULL) {
  1253.             $p_filename = $this->_tarname;
  1254.         }
  1255.         clearstatcache();
  1256.         return @is_file($p_filename);
  1257.     }
  1258.     // }}}
  1259.  
  1260.     // {{{ _openWrite()
  1261.     function _openWrite()
  1262.     {
  1263.         if ($this->_compress_type == 'gz')
  1264.             $this->_file = @gzopen($this->_tarname, "wb9");
  1265.         else if ($this->_compress_type == 'bz2')
  1266.             $this->_file = @bzopen($this->_tarname, "wb");
  1267.         else if ($this->_compress_type == 'none')
  1268.             $this->_file = @fopen($this->_tarname, "wb");
  1269.         else
  1270.             $this->_error('Unknown or missing compression type ('
  1271.                           .$this->_compress_type.')');
  1272.  
  1273.         if ($this->_file == 0) {
  1274.             $this->_error('Unable to open in write mode \''
  1275.                           .$this->_tarname.'\'');
  1276.             return false;
  1277.         }
  1278.  
  1279.         return true;
  1280.     }
  1281.     // }}}
  1282.  
  1283.     // {{{ _openRead()
  1284.     function _openRead()
  1285.     {
  1286.         if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
  1287.  
  1288.           // ----- Look if a local copy need to be done
  1289.           if ($this->_temp_tarname == '') {
  1290.               $this->_temp_tarname = uniqid('tar').'.tmp';
  1291.               if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
  1292.                 $this->_error('Unable to open in read mode \''
  1293.                               .$this->_tarname.'\'');
  1294.                 $this->_temp_tarname = '';
  1295.                 return false;
  1296.               }
  1297.               if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
  1298.                 $this->_error('Unable to open in write mode \''
  1299.                               .$this->_temp_tarname.'\'');
  1300.                 $this->_temp_tarname = '';
  1301.                 return false;
  1302.               }
  1303.               while ($v_data = @fread($v_file_from, 1024))
  1304.                   @fwrite($v_file_to, $v_data);
  1305.               @fclose($v_file_from);
  1306.               @fclose($v_file_to);
  1307.           }
  1308.  
  1309.           // ----- File to open if the local copy
  1310.           $v_filename = $this->_temp_tarname;
  1311.  
  1312.         } else
  1313.           // ----- File to open if the normal Tar file
  1314.           $v_filename = $this->_tarname;
  1315.  
  1316.         if ($this->_compress_type == 'gz')
  1317.             $this->_file = @gzopen($v_filename, "rb");
  1318.         else if ($this->_compress_type == 'bz2')
  1319.             $this->_file = @bzopen($v_filename, "rb");
  1320.         else if ($this->_compress_type == 'none')
  1321.             $this->_file = @fopen($v_filename, "rb");
  1322.         else
  1323.             $this->_error('Unknown or missing compression type ('
  1324.                           .$this->_compress_type.')');
  1325.  
  1326.         if ($this->_file == 0) {
  1327.             $this->_error('Unable to open in read mode \''.$v_filename.'\'');
  1328.             return false;
  1329.         }
  1330.  
  1331.         return true;
  1332.     }
  1333.     // }}}
  1334.  
  1335.     // {{{ _openReadWrite()
  1336.     function _openReadWrite()
  1337.     {
  1338.         if ($this->_compress_type == 'gz')
  1339.             $this->_file = @gzopen($this->_tarname, "r+b");
  1340.         else if ($this->_compress_type == 'bz2')
  1341.             $this->_file = @bzopen($this->_tarname, "r+b");
  1342.         else if ($this->_compress_type == 'none')
  1343.             $this->_file = @fopen($this->_tarname, "r+b");
  1344.         else
  1345.             $this->_error('Unknown or missing compression type ('
  1346.                           .$this->_compress_type.')');
  1347.  
  1348.         if ($this->_file == 0) {
  1349.             $this->_error('Unable to open in read/write mode \''
  1350.                           .$this->_tarname.'\'');
  1351.             return false;
  1352.         }
  1353.  
  1354.         return true;
  1355.     }
  1356.     // }}}
  1357.  
  1358.     // {{{ _close()
  1359.     function _close()
  1360.     {
  1361.         //if (isset($this->_file)) {
  1362.         if (is_resource($this->_file)) {
  1363.             if ($this->_compress_type == 'gz')
  1364.                 @gzclose($this->_file);
  1365.             else if ($this->_compress_type == 'bz2')
  1366.                 @bzclose($this->_file);
  1367.             else if ($this->_compress_type == 'none')
  1368.                 @fclose($this->_file);
  1369.             else
  1370.                 $this->_error('Unknown or missing compression type ('
  1371.                               .$this->_compress_type.')');
  1372.  
  1373.             $this->_file = 0;
  1374.         }
  1375.  
  1376.         // ----- Look if a local copy need to be erase
  1377.         // Note that it might be interesting to keep the url for a time : ToDo
  1378.         if ($this->_temp_tarname != '') {
  1379.             @unlink($this->_temp_tarname);
  1380.             $this->_temp_tarname = '';
  1381.         }
  1382.  
  1383.         return true;
  1384.     }
  1385.     // }}}
  1386.  
  1387.     // {{{ _cleanFile()
  1388.     function _cleanFile()
  1389.     {
  1390.         $this->_close();
  1391.  
  1392.         // ----- Look for a local copy
  1393.         if ($this->_temp_tarname != '') {
  1394.             // ----- Remove the local copy but not the remote tarname
  1395.             @unlink($this->_temp_tarname);
  1396.             $this->_temp_tarname = '';
  1397.         } else {
  1398.             // ----- Remove the local tarname file
  1399.             @unlink($this->_tarname);
  1400.         }
  1401.         $this->_tarname = '';
  1402.  
  1403.         return true;
  1404.     }
  1405.     // }}}
  1406.  
  1407.     // {{{ _writeBlock()
  1408.     function _writeBlock($p_binary_data, $p_len=null)
  1409.     {
  1410.       if (is_resource($this->_file)) {
  1411.           if ($p_len === null) {
  1412.               if ($this->_compress_type == 'gz')
  1413.                   @gzputs($this->_file, $p_binary_data);
  1414.               else if ($this->_compress_type == 'bz2')
  1415.                   @bzwrite($this->_file, $p_binary_data);
  1416.               else if ($this->_compress_type == 'none')
  1417.                   @fputs($this->_file, $p_binary_data);
  1418.               else
  1419.                   $this->_error('Unknown or missing compression type ('
  1420.                                 .$this->_compress_type.')');
  1421.           } else {
  1422.               if ($this->_compress_type == 'gz')
  1423.                   @gzputs($this->_file, $p_binary_data, $p_len);
  1424.               else if ($this->_compress_type == 'bz2')
  1425.                   @bzwrite($this->_file, $p_binary_data, $p_len);
  1426.               else if ($this->_compress_type == 'none')
  1427.                   @fputs($this->_file, $p_binary_data, $p_len);
  1428.               else
  1429.                   $this->_error('Unknown or missing compression type ('
  1430.                                 .$this->_compress_type.')');
  1431.  
  1432.           }
  1433.       }
  1434.       return true;
  1435.     }
  1436.     // }}}
  1437.  
  1438.     // {{{ _readBlock()
  1439.     function _readBlock()
  1440.     {
  1441.       $v_block = null;
  1442.       if (is_resource($this->_file)) {
  1443.           if ($this->_compress_type == 'gz')
  1444.               $v_block = @gzread($this->_file, 512);
  1445.           else if ($this->_compress_type == 'bz2')
  1446.               $v_block = @bzread($this->_file, 512);
  1447.           else if ($this->_compress_type == 'none')
  1448.               $v_block = @fread($this->_file, 512);
  1449.           else
  1450.               $this->_error('Unknown or missing compression type ('
  1451.                             .$this->_compress_type.')');
  1452.       }
  1453.       return $v_block;
  1454.     }
  1455.     // }}}
  1456.  
  1457.     // {{{ _jumpBlock()
  1458.     function _jumpBlock($p_len=null)
  1459.     {
  1460.       if (is_resource($this->_file)) {
  1461.           if ($p_len === null)
  1462.               $p_len = 1;
  1463.  
  1464.           if ($this->_compress_type == 'gz') {
  1465.               @gzseek($this->_file, @gztell($this->_file)+($p_len*512));
  1466.           }
  1467.           else if ($this->_compress_type == 'bz2') {
  1468.               // ----- Replace missing bztell() and bzseek()
  1469.               for ($i=0; $i<$p_len; $i++)
  1470.                   $this->_readBlock();
  1471.           } else if ($this->_compress_type == 'none')
  1472.               @fseek($this->_file, @ftell($this->_file)+($p_len*512));
  1473.           else
  1474.               $this->_error('Unknown or missing compression type ('
  1475.                             .$this->_compress_type.')');
  1476.  
  1477.       }
  1478.       return true;
  1479.     }
  1480.     // }}}
  1481.  
  1482.     // {{{ _writeFooter()
  1483.     function _writeFooter()
  1484.     {
  1485.       if (is_resource($this->_file)) {
  1486.           // ----- Write the last 0 filled block for end of archive
  1487.           $v_binary_data = pack("a512", '');
  1488.           $this->_writeBlock($v_binary_data);
  1489.       }
  1490.       return true;
  1491.     }
  1492.     // }}}
  1493.  
  1494.     // {{{ _addList()
  1495.     function _addList($p_list, $p_add_dir, $p_remove_dir)
  1496.     {
  1497.       $v_result=true;
  1498.       $v_header = array();
  1499.  
  1500.       // ----- Remove potential windows directory separator
  1501.       $p_add_dir = $this->_translateWinPath($p_add_dir);
  1502.       $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
  1503.  
  1504.       if (!$this->_file) {
  1505.           $this->_error('Invalid file descriptor');
  1506.           return false;
  1507.       }
  1508.  
  1509.       if (sizeof($p_list) == 0)
  1510.           return true;
  1511.  
  1512.       foreach ($p_list as $v_filename) {
  1513.           if (!$v_result) {
  1514.               break;
  1515.           }
  1516.  
  1517.         // ----- Skip the current tar name
  1518.         if ($v_filename == $this->_tarname)
  1519.             continue;
  1520.  
  1521.         if ($v_filename == '')
  1522.             continue;
  1523.  
  1524.         if (!file_exists($v_filename)) {
  1525.             $this->_warning("File '$v_filename' does not exist");
  1526.             continue;
  1527.         }
  1528.  
  1529.         // ----- Add the file or directory header
  1530.         if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
  1531.             return false;
  1532.  
  1533.         if (@is_dir($v_filename)) {
  1534.             if (!($p_hdir = opendir($v_filename))) {
  1535.                 $this->_warning("Directory '$v_filename' can not be read");
  1536.                 continue;
  1537.             }
  1538.             while (false !== ($p_hitem = readdir($p_hdir))) {
  1539.                 if (($p_hitem != '.') && ($p_hitem != '..')) {
  1540.                     if ($v_filename != ".")
  1541.                         $p_temp_list[0] = $v_filename.'/'.$p_hitem;
  1542.                     else
  1543.                         $p_temp_list[0] = $p_hitem;
  1544.  
  1545.                     $v_result = $this->_addList($p_temp_list,
  1546.                                                 $p_add_dir,
  1547.                                                 $p_remove_dir);
  1548.                 }
  1549.             }
  1550.  
  1551.             unset($p_temp_list);
  1552.             unset($p_hdir);
  1553.             unset($p_hitem);
  1554.         }
  1555.       }
  1556.  
  1557.       return $v_result;
  1558.     }
  1559.     // }}}
  1560.  
  1561.     // {{{ _addFile()
  1562.     function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir)
  1563.     {
  1564.       if (!$this->_file) {
  1565.           $this->_error('Invalid file descriptor');
  1566.           return false;
  1567.       }
  1568.  
  1569.       if ($p_filename == '') {
  1570.           $this->_error('Invalid file name');
  1571.           return false;
  1572.       }
  1573.  
  1574.       // ----- Calculate the stored filename
  1575.       $p_filename = $this->_translateWinPath($p_filename, false);;
  1576.       $v_stored_filename = $p_filename;
  1577.       if (strcmp($p_filename, $p_remove_dir) == 0) {
  1578.           return true;
  1579.       }
  1580.       if ($p_remove_dir != '') {
  1581.           if (substr($p_remove_dir, -1) != '/')
  1582.               $p_remove_dir .= '/';
  1583.  
  1584.           if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
  1585.               $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
  1586.       }
  1587.       $v_stored_filename = $this->_translateWinPath($v_stored_filename);
  1588.       if ($p_add_dir != '') {
  1589.           if (substr($p_add_dir, -1) == '/')
  1590.               $v_stored_filename = $p_add_dir.$v_stored_filename;
  1591.           else
  1592.               $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
  1593.       }
  1594.  
  1595.       $v_stored_filename = $this->_pathReduction($v_stored_filename);
  1596.  
  1597.       if ($this->_isArchive($p_filename)) {
  1598.           if (($v_file = @fopen($p_filename, "rb")) == 0) {
  1599.               $this->_warning("Unable to open file '".$p_filename
  1600.                               ."' in binary read mode");
  1601.               return true;
  1602.           }
  1603.  
  1604.           if (!$this->_writeHeader($p_filename, $v_stored_filename))
  1605.               return false;
  1606.  
  1607.           while (($v_buffer = fread($v_file, 512)) != '') {
  1608.               $v_binary_data = pack("a512", "$v_buffer");
  1609.               $this->_writeBlock($v_binary_data);
  1610.           }
  1611.  
  1612.           fclose($v_file);
  1613.  
  1614.       } else {
  1615.           // ----- Only header for dir
  1616.           if (!$this->_writeHeader($p_filename, $v_stored_filename))
  1617.               return false;
  1618.       }
  1619.  
  1620.       return true;
  1621.     }
  1622.     // }}}
  1623.  
  1624.     // {{{ _addString()
  1625.     function _addString($p_filename, $p_string)
  1626.     {
  1627.       if (!$this->_file) {
  1628.           $this->_error('Invalid file descriptor');
  1629.           return false;
  1630.       }
  1631.  
  1632.       if ($p_filename == '') {
  1633.           $this->_error('Invalid file name');
  1634.           return false;
  1635.       }
  1636.  
  1637.       // ----- Calculate the stored filename
  1638.       $p_filename = $this->_translateWinPath($p_filename, false);;
  1639.  
  1640.       if (!$this->_writeHeaderBlock($p_filename, strlen($p_string),
  1641.                                     0, 0, "", 0, 0))
  1642.           return false;
  1643.  
  1644.       $i=0;
  1645.       while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
  1646.           $v_binary_data = pack("a512", $v_buffer);
  1647.           $this->_writeBlock($v_binary_data);
  1648.       }
  1649.  
  1650.       return true;
  1651.     }
  1652.     // }}}
  1653.  
  1654.     // {{{ _writeHeader()
  1655.     function _writeHeader($p_filename, $p_stored_filename)
  1656.     {
  1657.         if ($p_stored_filename == '')
  1658.             $p_stored_filename = $p_filename;
  1659.         $v_reduce_filename = $this->_pathReduction($p_stored_filename);
  1660.  
  1661.         if (strlen($v_reduce_filename) > 99) {
  1662.           if (!$this->_writeLongHeader($v_reduce_filename))
  1663.             return false;
  1664.         }
  1665.  
  1666.         $v_info = stat($p_filename);
  1667.         $v_uid = sprintf("%6s ", DecOct($v_info[4]));
  1668.         $v_gid = sprintf("%6s ", DecOct($v_info[5]));
  1669.         $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename)));
  1670.  
  1671.         $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename)));
  1672.  
  1673.         if (@is_dir($p_filename)) {
  1674.           $v_typeflag = "5";
  1675.           $v_size = sprintf("%11s ", DecOct(0));
  1676.         } else {
  1677.           $v_typeflag = '';
  1678.           clearstatcache();
  1679.           $v_size = sprintf("%11s ", DecOct(filesize($p_filename)));
  1680.         }
  1681.  
  1682.         $v_linkname = '';
  1683.  
  1684.         $v_magic = '';
  1685.  
  1686.         $v_version = '';
  1687.  
  1688.         $v_uname = '';
  1689.  
  1690.         $v_gname = '';
  1691.  
  1692.         $v_devmajor = '';
  1693.  
  1694.         $v_devminor = '';
  1695.  
  1696.         $v_prefix = '';
  1697.  
  1698.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  1699.                                     $v_reduce_filename, $v_perms, $v_uid,
  1700.                                     $v_gid, $v_size, $v_mtime);
  1701.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  1702.                                    $v_typeflag, $v_linkname, $v_magic,
  1703.                                    $v_version, $v_uname, $v_gname,
  1704.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  1705.  
  1706.         // ----- Calculate the checksum
  1707.         $v_checksum = 0;
  1708.         // ..... First part of the header
  1709.         for ($i=0; $i<148; $i++)
  1710.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1711.         // ..... Ignore the checksum value and replace it by ' ' (space)
  1712.         for ($i=148; $i<156; $i++)
  1713.             $v_checksum += ord(' ');
  1714.         // ..... Last part of the header
  1715.         for ($i=156, $j=0; $i<512; $i++, $j++)
  1716.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1717.  
  1718.         // ----- Write the first 148 bytes of the header in the archive
  1719.         $this->_writeBlock($v_binary_data_first, 148);
  1720.  
  1721.         // ----- Write the calculated checksum
  1722.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  1723.         $v_binary_data = pack("a8", $v_checksum);
  1724.         $this->_writeBlock($v_binary_data, 8);
  1725.  
  1726.         // ----- Write the last 356 bytes of the header in the archive
  1727.         $this->_writeBlock($v_binary_data_last, 356);
  1728.  
  1729.         return true;
  1730.     }
  1731.     // }}}
  1732.  
  1733.     // {{{ _writeHeaderBlock()
  1734.     function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
  1735.                                $p_type='', $p_uid=0, $p_gid=0)
  1736.     {
  1737.         $p_filename = $this->_pathReduction($p_filename);
  1738.  
  1739.         if (strlen($p_filename) > 99) {
  1740.           if (!$this->_writeLongHeader($p_filename))
  1741.             return false;
  1742.         }
  1743.  
  1744.         if ($p_type == "5") {
  1745.           $v_size = sprintf("%11s ", DecOct(0));
  1746.         } else {
  1747.           $v_size = sprintf("%11s ", DecOct($p_size));
  1748.         }
  1749.  
  1750.         $v_uid = sprintf("%6s ", DecOct($p_uid));
  1751.         $v_gid = sprintf("%6s ", DecOct($p_gid));
  1752.         $v_perms = sprintf("%6s ", DecOct($p_perms));
  1753.  
  1754.         $v_mtime = sprintf("%11s", DecOct($p_mtime));
  1755.  
  1756.         $v_linkname = '';
  1757.  
  1758.         $v_magic = '';
  1759.  
  1760.         $v_version = '';
  1761.  
  1762.         $v_uname = '';
  1763.  
  1764.         $v_gname = '';
  1765.  
  1766.         $v_devmajor = '';
  1767.  
  1768.         $v_devminor = '';
  1769.  
  1770.         $v_prefix = '';
  1771.  
  1772.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  1773.                                     $p_filename, $v_perms, $v_uid, $v_gid,
  1774.                                     $v_size, $v_mtime);
  1775.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  1776.                                    $p_type, $v_linkname, $v_magic,
  1777.                                    $v_version, $v_uname, $v_gname,
  1778.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  1779.  
  1780.         // ----- Calculate the checksum
  1781.         $v_checksum = 0;
  1782.         // ..... First part of the header
  1783.         for ($i=0; $i<148; $i++)
  1784.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1785.         // ..... Ignore the checksum value and replace it by ' ' (space)
  1786.         for ($i=148; $i<156; $i++)
  1787.             $v_checksum += ord(' ');
  1788.         // ..... Last part of the header
  1789.         for ($i=156, $j=0; $i<512; $i++, $j++)
  1790.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1791.  
  1792.         // ----- Write the first 148 bytes of the header in the archive
  1793.         $this->_writeBlock($v_binary_data_first, 148);
  1794.  
  1795.         // ----- Write the calculated checksum
  1796.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  1797.         $v_binary_data = pack("a8", $v_checksum);
  1798.         $this->_writeBlock($v_binary_data, 8);
  1799.  
  1800.         // ----- Write the last 356 bytes of the header in the archive
  1801.         $this->_writeBlock($v_binary_data_last, 356);
  1802.  
  1803.         return true;
  1804.     }
  1805.     // }}}
  1806.  
  1807.     // {{{ _writeLongHeader()
  1808.     function _writeLongHeader($p_filename)
  1809.     {
  1810.         $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
  1811.  
  1812.         $v_typeflag = 'L';
  1813.  
  1814.         $v_linkname = '';
  1815.  
  1816.         $v_magic = '';
  1817.  
  1818.         $v_version = '';
  1819.  
  1820.         $v_uname = '';
  1821.  
  1822.         $v_gname = '';
  1823.  
  1824.         $v_devmajor = '';
  1825.  
  1826.         $v_devminor = '';
  1827.  
  1828.         $v_prefix = '';
  1829.  
  1830.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  1831.                                     '././@LongLink', 0, 0, 0, $v_size, 0);
  1832.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  1833.                                    $v_typeflag, $v_linkname, $v_magic,
  1834.                                    $v_version, $v_uname, $v_gname,
  1835.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  1836.  
  1837.         // ----- Calculate the checksum
  1838.         $v_checksum = 0;
  1839.         // ..... First part of the header
  1840.         for ($i=0; $i<148; $i++)
  1841.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  1842.         // ..... Ignore the checksum value and replace it by ' ' (space)
  1843.         for ($i=148; $i<156; $i++)
  1844.             $v_checksum += ord(' ');
  1845.         // ..... Last part of the header
  1846.         for ($i=156, $j=0; $i<512; $i++, $j++)
  1847.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  1848.  
  1849.         // ----- Write the first 148 bytes of the header in the archive
  1850.         $this->_writeBlock($v_binary_data_first, 148);
  1851.  
  1852.         // ----- Write the calculated checksum
  1853.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  1854.         $v_binary_data = pack("a8", $v_checksum);
  1855.         $this->_writeBlock($v_binary_data, 8);
  1856.  
  1857.         // ----- Write the last 356 bytes of the header in the archive
  1858.         $this->_writeBlock($v_binary_data_last, 356);
  1859.  
  1860.         // ----- Write the filename as content of the block
  1861.         $i=0;
  1862.         while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
  1863.             $v_binary_data = pack("a512", "$v_buffer");
  1864.             $this->_writeBlock($v_binary_data);
  1865.         }
  1866.  
  1867.         return true;
  1868.     }
  1869.     // }}}
  1870.  
  1871.     // {{{ _readHeader()
  1872.     function _readHeader($v_binary_data, &$v_header)
  1873.     {
  1874.         if (strlen($v_binary_data)==0) {
  1875.             $v_header['filename'] = '';
  1876.             return true;
  1877.         }
  1878.  
  1879.         if (strlen($v_binary_data) != 512) {
  1880.             $v_header['filename'] = '';
  1881.             $this->_error('Invalid block size : '.strlen($v_binary_data));
  1882.             return false;
  1883.         }
  1884.  
  1885.         if (!is_array($v_header)) {
  1886.             $v_header = array();
  1887.         }
  1888.         // ----- Calculate the checksum
  1889.         $v_checksum = 0;
  1890.         // ..... First part of the header
  1891.         for ($i=0; $i<148; $i++)
  1892.             $v_checksum+=ord(substr($v_binary_data,$i,1));
  1893.         // ..... Ignore the checksum value and replace it by ' ' (space)
  1894.         for ($i=148; $i<156; $i++)
  1895.             $v_checksum += ord(' ');
  1896.         // ..... Last part of the header
  1897.         for ($i=156; $i<512; $i++)
  1898.            $v_checksum+=ord(substr($v_binary_data,$i,1));
  1899.  
  1900.         $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/"
  1901.                          ."a8checksum/a1typeflag/a100link/a6magic/a2version/"
  1902.                          ."a32uname/a32gname/a8devmajor/a8devminor",
  1903.                          $v_binary_data);
  1904.  
  1905.         // ----- Extract the checksum
  1906.         $v_header['checksum'] = OctDec(trim($v_data['checksum']));
  1907.         if ($v_header['checksum'] != $v_checksum) {
  1908.             $v_header['filename'] = '';
  1909.  
  1910.             // ----- Look for last block (empty block)
  1911.             if (($v_checksum == 256) && ($v_header['checksum'] == 0))
  1912.                 return true;
  1913.  
  1914.             $this->_error('Invalid checksum for file "'.$v_data['filename']
  1915.                           .'" : '.$v_checksum.' calculated, '
  1916.                           .$v_header['checksum'].' expected');
  1917.             return false;
  1918.         }
  1919.  
  1920.         // ----- Extract the properties
  1921.         $v_header['filename'] = trim($v_data['filename']);
  1922.         $v_header['mode'] = OctDec(trim($v_data['mode']));
  1923.         $v_header['uid'] = OctDec(trim($v_data['uid']));
  1924.         $v_header['gid'] = OctDec(trim($v_data['gid']));
  1925.         $v_header['size'] = OctDec(trim($v_data['size']));
  1926.         $v_header['mtime'] = OctDec(trim($v_data['mtime']));
  1927.         if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
  1928.           $v_header['size'] = 0;
  1929.         }
  1930.         /* ----- All these fields are removed form the header because
  1931.         they do not carry interesting info
  1932.         $v_header[link] = trim($v_data[link]);
  1933.         $v_header[magic] = trim($v_data[magic]);
  1934.         $v_header[version] = trim($v_data[version]);
  1935.         $v_header[uname] = trim($v_data[uname]);
  1936.         $v_header[gname] = trim($v_data[gname]);
  1937.         $v_header[devmajor] = trim($v_data[devmajor]);
  1938.         $v_header[devminor] = trim($v_data[devminor]);
  1939.         */
  1940.  
  1941.         return true;
  1942.     }
  1943.     // }}}
  1944.  
  1945.     // {{{ _readLongHeader()
  1946.     function _readLongHeader(&$v_header)
  1947.     {
  1948.       $v_filename = '';
  1949.       $n = floor($v_header['size']/512);
  1950.       for ($i=0; $i<$n; $i++) {
  1951.         $v_content = $this->_readBlock();
  1952.         $v_filename .= $v_content;
  1953.       }
  1954.       if (($v_header['size'] % 512) != 0) {
  1955.         $v_content = $this->_readBlock();
  1956.         $v_filename .= $v_content;
  1957.       }
  1958.  
  1959.       // ----- Read the next header
  1960.       $v_binary_data = $this->_readBlock();
  1961.  
  1962.       if (!$this->_readHeader($v_binary_data, $v_header))
  1963.         return false;
  1964.  
  1965.       $v_header['filename'] = $v_filename;
  1966.  
  1967.       return true;
  1968.     }
  1969.     // }}}
  1970.  
  1971.     // {{{ _extractInString()
  1972.     /**
  1973.     * This method extract from the archive one file identified by $p_filename.
  1974.     * The return value is a string with the file content, or NULL on error.
  1975.     * @param string $p_filename     The path of the file to extract in a string.
  1976.     * @return                       a string with the file content or NULL.
  1977.     * @access private
  1978.     */
  1979.     function _extractInString($p_filename)
  1980.     {
  1981.         $v_result_str = "";
  1982.  
  1983.         While (strlen($v_binary_data = $this->_readBlock()) != 0)
  1984.         {
  1985.           if (!$this->_readHeader($v_binary_data, $v_header))
  1986.             return NULL;
  1987.  
  1988.           if ($v_header['filename'] == '')
  1989.             continue;
  1990.  
  1991.           // ----- Look for long filename
  1992.           if ($v_header['typeflag'] == 'L') {
  1993.             if (!$this->_readLongHeader($v_header))
  1994.               return NULL;
  1995.           }
  1996.  
  1997.           if ($v_header['filename'] == $p_filename) {
  1998.               if ($v_header['typeflag'] == "5") {
  1999.                   $this->_error('Unable to extract in string a directory '
  2000.                                 .'entry {'.$v_header['filename'].'}');
  2001.                   return NULL;
  2002.               } else {
  2003.                   $n = floor($v_header['size']/512);
  2004.                   for ($i=0; $i<$n; $i++) {
  2005.                       $v_result_str .= $this->_readBlock();
  2006.                   }
  2007.                   if (($v_header['size'] % 512) != 0) {
  2008.                       $v_content = $this->_readBlock();
  2009.                       $v_result_str .= substr($v_content, 0,
  2010.                                               ($v_header['size'] % 512));
  2011.                   }
  2012.                   return $v_result_str;
  2013.               }
  2014.           } else {
  2015.               $this->_jumpBlock(ceil(($v_header['size']/512)));
  2016.           }
  2017.         }
  2018.  
  2019.         return NULL;
  2020.     }
  2021.     // }}}
  2022.  
  2023.     // {{{ _extractList()
  2024.     function _extractList($p_path, &$p_list_detail, $p_mode,
  2025.                           $p_file_list, $p_remove_path)
  2026.     {
  2027.     $v_result=true;
  2028.     $v_nb = 0;
  2029.     $v_extract_all = true;
  2030.     $v_listing = false;
  2031.  
  2032.     $p_path = $this->_translateWinPath($p_path, false);
  2033.     if ($p_path == '' || (substr($p_path, 0, 1) != '/'
  2034.         && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
  2035.       $p_path = "./".$p_path;
  2036.     }
  2037.     $p_remove_path = $this->_translateWinPath($p_remove_path);
  2038.  
  2039.     // ----- Look for path to remove format (should end by /)
  2040.     if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
  2041.       $p_remove_path .= '/';
  2042.     $p_remove_path_size = strlen($p_remove_path);
  2043.  
  2044.     switch ($p_mode) {
  2045.       case "complete" :
  2046.         $v_extract_all = TRUE;
  2047.         $v_listing = FALSE;
  2048.       break;
  2049.       case "partial" :
  2050.           $v_extract_all = FALSE;
  2051.           $v_listing = FALSE;
  2052.       break;
  2053.       case "list" :
  2054.           $v_extract_all = FALSE;
  2055.           $v_listing = TRUE;
  2056.       break;
  2057.       default :
  2058.         $this->_error('Invalid extract mode ('.$p_mode.')');
  2059.         return false;
  2060.     }
  2061.  
  2062.     clearstatcache();
  2063.  
  2064.     while (strlen($v_binary_data = $this->_readBlock()) != 0)
  2065.     {
  2066.       $v_extract_file = FALSE;
  2067.       $v_extraction_stopped = 0;
  2068.  
  2069.       if (!$this->_readHeader($v_binary_data, $v_header))
  2070.         return false;
  2071.  
  2072.       if ($v_header['filename'] == '') {
  2073.         continue;
  2074.       }
  2075.  
  2076.       // ----- Look for long filename
  2077.       if ($v_header['typeflag'] == 'L') {
  2078.         if (!$this->_readLongHeader($v_header))
  2079.           return false;
  2080.       }
  2081.  
  2082.       if ((!$v_extract_all) && (is_array($p_file_list))) {
  2083.         // ----- By default no unzip if the file is not found
  2084.         $v_extract_file = false;
  2085.  
  2086.         for ($i=0; $i<sizeof($p_file_list); $i++) {
  2087.           // ----- Look if it is a directory
  2088.           if (substr($p_file_list[$i], -1) == '/') {
  2089.             // ----- Look if the directory is in the filename path
  2090.             if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
  2091.                 && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
  2092.                     == $p_file_list[$i])) {
  2093.               $v_extract_file = TRUE;
  2094.               break;
  2095.             }
  2096.           }
  2097.  
  2098.           // ----- It is a file, so compare the file names
  2099.           elseif ($p_file_list[$i] == $v_header['filename']) {
  2100.             $v_extract_file = TRUE;
  2101.             break;
  2102.           }
  2103.         }
  2104.       } else {
  2105.         $v_extract_file = TRUE;
  2106.       }
  2107.  
  2108.       // ----- Look if this file need to be extracted
  2109.       if (($v_extract_file) && (!$v_listing))
  2110.       {
  2111.         if (($p_remove_path != '')
  2112.             && (substr($v_header['filename'], 0, $p_remove_path_size)
  2113.                 == $p_remove_path))
  2114.           $v_header['filename'] = substr($v_header['filename'],
  2115.                                          $p_remove_path_size);
  2116.         if (($p_path != './') && ($p_path != '/')) {
  2117.           while (substr($p_path, -1) == '/')
  2118.             $p_path = substr($p_path, 0, strlen($p_path)-1);
  2119.  
  2120.           if (substr($v_header['filename'], 0, 1) == '/')
  2121.               $v_header['filename'] = $p_path.$v_header['filename'];
  2122.           else
  2123.             $v_header['filename'] = $p_path.'/'.$v_header['filename'];
  2124.         }
  2125.         if (file_exists($v_header['filename'])) {
  2126.           if (   (@is_dir($v_header['filename']))
  2127.               && ($v_header['typeflag'] == '')) {
  2128.             $this->_error('File '.$v_header['filename']
  2129.                           .' already exists as a directory');
  2130.             return false;
  2131.           }
  2132.           if (   ($this->_isArchive($v_header['filename']))
  2133.               && ($v_header['typeflag'] == "5")) {
  2134.             $this->_error('Directory '.$v_header['filename']
  2135.                           .' already exists as a file');
  2136.             return false;
  2137.           }
  2138.           if (!is_writeable($v_header['filename'])) {
  2139.             $this->_error('File '.$v_header['filename']
  2140.                           .' already exists and is write protected');
  2141.             return false;
  2142.           }
  2143.           if (filemtime($v_header['filename']) > $v_header['mtime']) {
  2144.             // To be completed : An error or silent no replace ?
  2145.           }
  2146.         }
  2147.  
  2148.         // ----- Check the directory availability and create it if necessary
  2149.         elseif (($v_result
  2150.                  = $this->_dirCheck(($v_header['typeflag'] == "5"
  2151.                                     ?$v_header['filename']
  2152.                                     :dirname($v_header['filename'])))) != 1) {
  2153.             $this->_error('Unable to create path for '.$v_header['filename']);
  2154.             return false;
  2155.         }
  2156.  
  2157.         if ($v_extract_file) {
  2158.           if ($v_header['typeflag'] == "5") {
  2159.             if (!@file_exists($v_header['filename'])) {
  2160.                 if (!@mkdir($v_header['filename'], 0777)) {
  2161.                     $this->_error('Unable to create directory {'
  2162.                                   .$v_header['filename'].'}');
  2163.                     return false;
  2164.                 }
  2165.             }
  2166.           } else {
  2167.               if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
  2168.                   $this->_error('Error while opening {'.$v_header['filename']
  2169.                                 .'} in write binary mode');
  2170.                   return false;
  2171.               } else {
  2172.                   $n = floor($v_header['size']/512);
  2173.                   for ($i=0; $i<$n; $i++) {
  2174.                       $v_content = $this->_readBlock();
  2175.                       fwrite($v_dest_file, $v_content, 512);
  2176.                   }
  2177.             if (($v_header['size'] % 512) != 0) {
  2178.               $v_content = $this->_readBlock();
  2179.               fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
  2180.             }
  2181.  
  2182.             @fclose($v_dest_file);
  2183.  
  2184.             // ----- Change the file mode, mtime
  2185.             @touch($v_header['filename'], $v_header['mtime']);
  2186.             // To be completed
  2187.             //chmod($v_header[filename], DecOct($v_header[mode]));
  2188.           }
  2189.  
  2190.           // ----- Check the file size
  2191.           clearstatcache();
  2192.           if (filesize($v_header['filename']) != $v_header['size']) {
  2193.               $this->_error('Extracted file '.$v_header['filename']
  2194.                             .' does not have the correct file size \''
  2195.                             .filesize($v_header['filename'])
  2196.                             .'\' ('.$v_header['size']
  2197.                             .' expected). Archive may be corrupted.');
  2198.               return false;
  2199.           }
  2200.           }
  2201.         } else {
  2202.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  2203.         }
  2204.       } else {
  2205.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  2206.       }
  2207.  
  2208.       /* TBC : Seems to be unused ...
  2209.       if ($this->_compress)
  2210.         $v_end_of_file = @gzeof($this->_file);
  2211.       else
  2212.         $v_end_of_file = @feof($this->_file);
  2213.         */
  2214.  
  2215.       if ($v_listing || $v_extract_file || $v_extraction_stopped) {
  2216.         // ----- Log extracted files
  2217.         if (($v_file_dir = dirname($v_header['filename']))
  2218.             == $v_header['filename'])
  2219.           $v_file_dir = '';
  2220.         if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
  2221.           $v_file_dir = '/';
  2222.  
  2223.         $p_list_detail[$v_nb++] = $v_header;
  2224.       }
  2225.     }
  2226.  
  2227.         return true;
  2228.     }
  2229.     // }}}
  2230.  
  2231.     // {{{ _openAppend()
  2232.     function _openAppend()
  2233.     {
  2234.         if (filesize($this->_tarname) == 0)
  2235.           return $this->_openWrite();
  2236.           
  2237.         if ($this->_compress) {
  2238.             $this->_close();
  2239.  
  2240.             if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
  2241.                 $this->_error('Error while renaming \''.$this->_tarname
  2242.                               .'\' to temporary file \''.$this->_tarname
  2243.                               .'.tmp\'');
  2244.                 return false;
  2245.             }
  2246.  
  2247.             if ($this->_compress_type == 'gz')
  2248.                 $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
  2249.             elseif ($this->_compress_type == 'bz2')
  2250.                 $v_temp_tar = @bzopen($this->_tarname.".tmp", "rb");
  2251.                 
  2252.             if ($v_temp_tar == 0) {
  2253.                 $this->_error('Unable to open file \''.$this->_tarname
  2254.                               .'.tmp\' in binary read mode');
  2255.                 @rename($this->_tarname.".tmp", $this->_tarname);
  2256.                 return false;
  2257.             }
  2258.  
  2259.             if (!$this->_openWrite()) {
  2260.                 @rename($this->_tarname.".tmp", $this->_tarname);
  2261.                 return false;
  2262.             }
  2263.  
  2264.             if ($this->_compress_type == 'gz') {
  2265.                 $v_buffer = @gzread($v_temp_tar, 512);
  2266.  
  2267.                 // ----- Read the following blocks but not the last one
  2268.                 if (!@gzeof($v_temp_tar)) {
  2269.                     do{
  2270.                         $v_binary_data = pack("a512", $v_buffer);
  2271.                         $this->_writeBlock($v_binary_data);
  2272.                         $v_buffer = @gzread($v_temp_tar, 512);
  2273.  
  2274.                     } while (!@gzeof($v_temp_tar));
  2275.                 }
  2276.  
  2277.                 @gzclose($v_temp_tar);
  2278.             }
  2279.             elseif ($this->_compress_type == 'bz2') {
  2280.                 $v_buffered_lines   = array();
  2281.                 $v_buffered_lines[] = @bzread($v_temp_tar, 512);
  2282.  
  2283.                 // ----- Read the following blocks but not the last one
  2284.                 while (strlen($v_buffered_lines[]
  2285.                               = @bzread($v_temp_tar, 512)) > 0) {
  2286.                     $v_binary_data = pack("a512",
  2287.                                           array_shift($v_buffered_lines));
  2288.                     $this->_writeBlock($v_binary_data);
  2289.                 }
  2290.  
  2291.                 @bzclose($v_temp_tar);
  2292.             }
  2293.  
  2294.             if (!@unlink($this->_tarname.".tmp")) {
  2295.                 $this->_error('Error while deleting temporary file \''
  2296.                               .$this->_tarname.'.tmp\'');
  2297.             }
  2298.  
  2299.         } else {
  2300.             // ----- For not compressed tar, just add files before the last
  2301.             //       512 bytes block
  2302.             if (!$this->_openReadWrite())
  2303.                return false;
  2304.  
  2305.             clearstatcache();
  2306.             $v_size = filesize($this->_tarname);
  2307.             fseek($this->_file, $v_size-512);
  2308.         }
  2309.  
  2310.         return true;
  2311.     }
  2312.     // }}}
  2313.  
  2314.     // {{{ _append()
  2315.     function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
  2316.     {
  2317.         if (!$this->_openAppend())
  2318.             return false;
  2319.             
  2320.         if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
  2321.            $this->_writeFooter();
  2322.  
  2323.         $this->_close();
  2324.  
  2325.         return true;
  2326.     }
  2327.     // }}}
  2328.  
  2329.     // {{{ _dirCheck()
  2330.  
  2331.     /**
  2332.      * Check if a directory exists and create it (including parent
  2333.      * dirs) if not.
  2334.      *
  2335.      * @param string $p_dir directory to check
  2336.      *
  2337.      * @return bool TRUE if the directory exists or was created
  2338.      */
  2339.     function _dirCheck($p_dir)
  2340.     {
  2341.         if ((@is_dir($p_dir)) || ($p_dir == ''))
  2342.             return true;
  2343.  
  2344.         $p_parent_dir = dirname($p_dir);
  2345.  
  2346.         if (($p_parent_dir != $p_dir) &&
  2347.             ($p_parent_dir != '') &&
  2348.             (!$this->_dirCheck($p_parent_dir)))
  2349.              return false;
  2350.  
  2351.         if (!@mkdir($p_dir, 0777)) {
  2352.             $this->_error("Unable to create directory '$p_dir'");
  2353.             return false;
  2354.         }
  2355.  
  2356.         return true;
  2357.     }
  2358.  
  2359.     // }}}
  2360.  
  2361.     // {{{ _pathReduction()
  2362.  
  2363.     /**
  2364.      * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", 
  2365.      * rand emove double slashes.
  2366.      *
  2367.      * @param string $p_dir path to reduce
  2368.      *
  2369.      * @return string reduced path
  2370.      *
  2371.      * @access private
  2372.      *
  2373.      */
  2374.     function _pathReduction($p_dir)
  2375.     {
  2376.         $v_result = '';
  2377.  
  2378.         // ----- Look for not empty path
  2379.         if ($p_dir != '') {
  2380.             // ----- Explode path by directory names
  2381.             $v_list = explode('/', $p_dir);
  2382.  
  2383.             // ----- Study directories from last to first
  2384.             for ($i=sizeof($v_list)-1; $i>=0; $i--) {
  2385.                 // ----- Look for current path
  2386.                 if ($v_list[$i] == ".") {
  2387.                     // ----- Ignore this directory
  2388.                     // Should be the first $i=0, but no check is done
  2389.                 }
  2390.                 else if ($v_list[$i] == "..") {
  2391.                     // ----- Ignore it and ignore the $i-1
  2392.                     $i--;
  2393.                 }
  2394.                 else if (   ($v_list[$i] == '')
  2395.                          && ($i!=(sizeof($v_list)-1))
  2396.                          && ($i!=0)) {
  2397.                     // ----- Ignore only the double '//' in path,
  2398.                     // but not the first and last /
  2399.                 } else {
  2400.                     $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
  2401.                                 .$v_result:'');
  2402.                 }
  2403.             }
  2404.         }
  2405.         $v_result = strtr($v_result, '\\', '/');
  2406.         return $v_result;
  2407.     }
  2408.  
  2409.     // }}}
  2410.  
  2411.     // {{{ _translateWinPath()
  2412.     function _translateWinPath($p_path, $p_remove_disk_letter=true)
  2413.     {
  2414.       if (OS_WINDOWS) {
  2415.           // ----- Look for potential disk letter
  2416.           if (   ($p_remove_disk_letter)
  2417.               && (($v_position = strpos($p_path, ':')) != false)) {
  2418.               $p_path = substr($p_path, $v_position+1);
  2419.           }
  2420.           // ----- Change potential windows directory separator
  2421.           if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
  2422.               $p_path = strtr($p_path, '\\', '/');
  2423.           }
  2424.       }
  2425.       return $p_path;
  2426.     }
  2427.     // }}}
  2428.  
  2429. }
  2430. ?>
  2431. <?php
  2432. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  2433. // +----------------------------------------------------------------------+
  2434. // | PHP Version 5                                                        |
  2435. // +----------------------------------------------------------------------+
  2436. // | Copyright (c) 1997-2004 The PHP Group                                |
  2437. // +----------------------------------------------------------------------+
  2438. // | This source file is subject to version 3.0 of the PHP license,       |
  2439. // | that is bundled with this package in the file LICENSE, and is        |
  2440. // | available through the world-wide-web at the following url:           |
  2441. // | http://www.php.net/license/3_0.txt.                                  |
  2442. // | If you did not receive a copy of the PHP license and are unable to   |
  2443. // | obtain it through the world-wide-web, please send a note to          |
  2444. // | license@php.net so we can mail you a copy immediately.               |
  2445. // +----------------------------------------------------------------------+
  2446. // | Author: Andrei Zmievski <andrei@php.net>                             |
  2447. // +----------------------------------------------------------------------+
  2448. //
  2449. // $Id: Getopt.php,v 1.28 2004/01/08 17:33:10 sniper Exp $
  2450.  
  2451. require_once 'phar://go-pear.phar/PEAR.php';
  2452.  
  2453. /**
  2454.  * Command-line options parsing class.
  2455.  *
  2456.  * @author Andrei Zmievski <andrei@php.net>
  2457.  *
  2458.  */
  2459. class Console_Getopt {
  2460.     /**
  2461.      * Parses the command-line options.
  2462.      *
  2463.      * The first parameter to this function should be the list of command-line
  2464.      * arguments without the leading reference to the running program.
  2465.      *
  2466.      * The second parameter is a string of allowed short options. Each of the
  2467.      * option letters can be followed by a colon ':' to specify that the option
  2468.      * requires an argument, or a double colon '::' to specify that the option
  2469.      * takes an optional argument.
  2470.      *
  2471.      * The third argument is an optional array of allowed long options. The
  2472.      * leading '--' should not be included in the option name. Options that
  2473.      * require an argument should be followed by '=', and options that take an
  2474.      * option argument should be followed by '=='.
  2475.      *
  2476.      * The return value is an array of two elements: the list of parsed
  2477.      * options and the list of non-option command-line arguments. Each entry in
  2478.      * the list of parsed options is a pair of elements - the first one
  2479.      * specifies the option, and the second one specifies the option argument,
  2480.      * if there was one.
  2481.      *
  2482.      * Long and short options can be mixed.
  2483.      *
  2484.      * Most of the semantics of this function are based on GNU getopt_long().
  2485.      *
  2486.      * @param array  $args           an array of command-line arguments
  2487.      * @param string $short_options  specifies the list of allowed short options
  2488.      * @param array  $long_options   specifies the list of allowed long options
  2489.      *
  2490.      * @return array two-element array containing the list of parsed options and
  2491.      * the non-option arguments
  2492.      *
  2493.      * @access public
  2494.      *
  2495.      */
  2496.     function getopt2($args, $short_options, $long_options = null)
  2497.     {
  2498.         return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
  2499.     }
  2500.  
  2501.     /**
  2502.      * This function expects $args to start with the script name (POSIX-style).
  2503.      * Preserved for backwards compatibility.
  2504.      * @see getopt2()
  2505.      */    
  2506.     function getopt($args, $short_options, $long_options = null)
  2507.     {
  2508.         return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
  2509.     }
  2510.  
  2511.     /**
  2512.      * The actual implementation of the argument parsing code.
  2513.      */
  2514.     function doGetopt($version, $args, $short_options, $long_options = null)
  2515.     {
  2516.         // in case you pass directly readPHPArgv() as the first arg
  2517.         if (PEAR::isError($args)) {
  2518.             return $args;
  2519.         }
  2520.         if (empty($args)) {
  2521.             return array(array(), array());
  2522.         }
  2523.         $opts     = array();
  2524.         $non_opts = array();
  2525.  
  2526.         settype($args, 'array');
  2527.  
  2528.         if ($long_options) {
  2529.             sort($long_options);
  2530.         }
  2531.  
  2532.         /*
  2533.          * Preserve backwards compatibility with callers that relied on
  2534.          * erroneous POSIX fix.
  2535.          */
  2536.         if ($version < 2) {
  2537.             if (isset($args[0]{0}) && $args[0]{0} != '-') {
  2538.                 array_shift($args);
  2539.             }
  2540.         }
  2541.  
  2542.         reset($args);
  2543.         while (list($i, $arg) = each($args)) {
  2544.  
  2545.             /* The special element '--' means explicit end of
  2546.                options. Treat the rest of the arguments as non-options
  2547.                and end the loop. */
  2548.             if ($arg == '--') {
  2549.                 $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
  2550.                 break;
  2551.             }
  2552.  
  2553.             if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
  2554.                 $non_opts = array_merge($non_opts, array_slice($args, $i));
  2555.                 break;
  2556.             } elseif (strlen($arg) > 1 && $arg{1} == '-') {
  2557.                 $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
  2558.                 if (PEAR::isError($error))
  2559.                     return $error;
  2560.             } else {
  2561.                 $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
  2562.                 if (PEAR::isError($error))
  2563.                     return $error;
  2564.             }
  2565.         }
  2566.  
  2567.         return array($opts, $non_opts);
  2568.     }
  2569.  
  2570.     /**
  2571.      * @access private
  2572.      *
  2573.      */
  2574.     function _parseShortOption($arg, $short_options, &$opts, &$args)
  2575.     {
  2576.         for ($i = 0; $i < strlen($arg); $i++) {
  2577.             $opt = $arg{$i};
  2578.             $opt_arg = null;
  2579.  
  2580.             /* Try to find the short option in the specifier string. */
  2581.             if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
  2582.             {
  2583.                 return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
  2584.             }
  2585.  
  2586.             if (strlen($spec) > 1 && $spec{1} == ':') {
  2587.                 if (strlen($spec) > 2 && $spec{2} == ':') {
  2588.                     if ($i + 1 < strlen($arg)) {
  2589.                         /* Option takes an optional argument. Use the remainder of
  2590.                            the arg string if there is anything left. */
  2591.                         $opts[] = array($opt, substr($arg, $i + 1));
  2592.                         break;
  2593.                     }
  2594.                 } else {
  2595.                     /* Option requires an argument. Use the remainder of the arg
  2596.                        string if there is anything left. */
  2597.                     if ($i + 1 < strlen($arg)) {
  2598.                         $opts[] = array($opt,  substr($arg, $i + 1));
  2599.                         break;
  2600.                     } else if (list(, $opt_arg) = each($args))
  2601.                         /* Else use the next argument. */;
  2602.                     else
  2603.                         return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
  2604.                 }
  2605.             }
  2606.  
  2607.             $opts[] = array($opt, $opt_arg);
  2608.         }
  2609.     }
  2610.  
  2611.     /**
  2612.      * @access private
  2613.      *
  2614.      */
  2615.     function _parseLongOption($arg, $long_options, &$opts, &$args)
  2616.     {
  2617.         @list($opt, $opt_arg) = explode('=', $arg);
  2618.         $opt_len = strlen($opt);
  2619.  
  2620.         for ($i = 0; $i < count($long_options); $i++) {
  2621.             $long_opt  = $long_options[$i];
  2622.             $opt_start = substr($long_opt, 0, $opt_len);
  2623.  
  2624.             /* Option doesn't match. Go on to the next one. */
  2625.             if ($opt_start != $opt)
  2626.                 continue;
  2627.  
  2628.             $opt_rest  = substr($long_opt, $opt_len);
  2629.  
  2630.             /* Check that the options uniquely matches one of the allowed
  2631.                options. */
  2632.             if ($opt_rest != '' && $opt{0} != '=' &&
  2633.                 $i + 1 < count($long_options) &&
  2634.                 $opt == substr($long_options[$i+1], 0, $opt_len)) {
  2635.                 return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous");
  2636.             }
  2637.  
  2638.             if (substr($long_opt, -1) == '=') {
  2639.                 if (substr($long_opt, -2) != '==') {
  2640.                     /* Long option requires an argument.
  2641.                        Take the next argument if one wasn't specified. */;
  2642.                     if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
  2643.                         return PEAR::raiseError("Console_Getopt: option --$opt requires an argument");
  2644.                     }
  2645.                 }
  2646.             } else if ($opt_arg) {
  2647.                 return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
  2648.             }
  2649.  
  2650.             $opts[] = array('--' . $opt, $opt_arg);
  2651.             return;
  2652.         }
  2653.  
  2654.         return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
  2655.     }
  2656.  
  2657.     /**
  2658.     * Safely read the $argv PHP array across different PHP configurations.
  2659.     * Will take care on register_globals and register_argc_argv ini directives
  2660.     *
  2661.     * @access public
  2662.     * @return mixed the $argv PHP array or PEAR error if not registered
  2663.     */
  2664.     function readPHPArgv()
  2665.     {
  2666.         global $argv;
  2667.         if (!is_array($argv)) {
  2668.             if (!@is_array($_SERVER['argv'])) {
  2669.                 if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
  2670.                     return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
  2671.                 }
  2672.                 return $GLOBALS['HTTP_SERVER_VARS']['argv'];
  2673.             }
  2674.             return $_SERVER['argv'];
  2675.         }
  2676.         return $argv;
  2677.     }
  2678.  
  2679. }
  2680.  
  2681. ?>
  2682. <?php
  2683. require_once 'phar://go-pear.phar/PEAR/Start/CLI.php';
  2684. PEAR::setErrorHandling(PEAR_ERROR_DIE);
  2685. $a = new PEAR_Start_CLI;
  2686. $a->run();
  2687. ?><?php
  2688. /**
  2689.  * The OS_Guess class
  2690.  *
  2691.  * PHP versions 4 and 5
  2692.  *
  2693.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  2694.  * that is available through the world-wide-web at the following URI:
  2695.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  2696.  * the PHP License and are unable to obtain it through the web, please
  2697.  * send a note to license@php.net so we can mail you a copy immediately.
  2698.  *
  2699.  * @category   pear
  2700.  * @package    PEAR
  2701.  * @author     Stig Bakken <ssb@php.net>
  2702.  * @author     Gregory Beaver <cellog@php.net>
  2703.  * @copyright  1997-2005 The PHP Group
  2704.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  2705.  * @version    CVS: $Id: Guess.php,v 1.23 2006/06/16 11:42:16 pajoye Exp $
  2706.  * @link       http://pear.php.net/package/PEAR
  2707.  * @since      File available since PEAR 0.1
  2708.  */
  2709.  
  2710. // {{{ uname examples
  2711.  
  2712. // php_uname() without args returns the same as 'uname -a', or a PHP-custom
  2713. // string for Windows.
  2714. // PHP versions prior to 4.3 return the uname of the host where PHP was built,
  2715. // as of 4.3 it returns the uname of the host running the PHP code.
  2716. //
  2717. // PC RedHat Linux 7.1:
  2718. // Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
  2719. //
  2720. // PC Debian Potato:
  2721. // Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
  2722. //
  2723. // PC FreeBSD 3.3:
  2724. // FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000     root@example.com:/usr/src/sys/compile/CONFIG  i386
  2725. //
  2726. // PC FreeBSD 4.3:
  2727. // FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001     root@example.com:/usr/src/sys/compile/CONFIG  i386
  2728. //
  2729. // PC FreeBSD 4.5:
  2730. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb  6 23:59:23 CET 2002     root@example.com:/usr/src/sys/compile/CONFIG  i386
  2731. //
  2732. // PC FreeBSD 4.5 w/uname from GNU shellutils:
  2733. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb  i386 unknown
  2734. //
  2735. // HP 9000/712 HP-UX 10:
  2736. // HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
  2737. //
  2738. // HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
  2739. // HP-UX host B.10.10 A 9000/712 unknown
  2740. //
  2741. // IBM RS6000/550 AIX 4.3:
  2742. // AIX host 3 4 000003531C00
  2743. //
  2744. // AIX 4.3 w/uname from GNU shellutils:
  2745. // AIX host 3 4 000003531C00 unknown
  2746. //
  2747. // SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
  2748. // IRIX64 host 6.5 01091820 IP19 mips
  2749. //
  2750. // SGI Onyx IRIX 6.5:
  2751. // IRIX64 host 6.5 01091820 IP19
  2752. //
  2753. // SparcStation 20 Solaris 8 w/uname from GNU shellutils:
  2754. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
  2755. //
  2756. // SparcStation 20 Solaris 8:
  2757. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
  2758. //
  2759. // Mac OS X (Darwin)
  2760. // Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug  5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC  Power Macintosh
  2761. //
  2762. // Mac OS X early versions
  2763. // 
  2764.  
  2765. // }}}
  2766.  
  2767. /* TODO:
  2768.  * - define endianness, to allow matchSignature("bigend") etc.
  2769.  */
  2770.  
  2771. /**
  2772.  * Retrieves information about the current operating system
  2773.  *
  2774.  * This class uses php_uname() to grok information about the current OS
  2775.  *
  2776.  * @category   pear
  2777.  * @package    PEAR
  2778.  * @author     Stig Bakken <ssb@php.net>
  2779.  * @author     Gregory Beaver <cellog@php.net>
  2780.  * @copyright  1997-2005 The PHP Group
  2781.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  2782.  * @version    Release: 1.5.0a2
  2783.  * @link       http://pear.php.net/package/PEAR
  2784.  * @since      Class available since Release 0.1
  2785.  */
  2786. class OS_Guess
  2787. {
  2788.     var $sysname;
  2789.     var $nodename;
  2790.     var $cpu;
  2791.     var $release;
  2792.     var $extra;
  2793.  
  2794.     function OS_Guess($uname = null)
  2795.     {
  2796.         list($this->sysname,
  2797.              $this->release,
  2798.              $this->cpu,
  2799.              $this->extra,
  2800.              $this->nodename) = $this->parseSignature($uname);
  2801.     }
  2802.  
  2803.     function parseSignature($uname = null)
  2804.     {
  2805.         static $sysmap = array(
  2806.             'HP-UX' => 'hpux',
  2807.             'IRIX64' => 'irix',
  2808.         );
  2809.         static $cpumap = array(
  2810.             'i586' => 'i386',
  2811.             'i686' => 'i386',
  2812.             'ppc' => 'powerpc',
  2813.         );
  2814.         if ($uname === null) {
  2815.             $uname = php_uname();
  2816.         }
  2817.         $parts = split('[[:space:]]+', trim($uname));
  2818.         $n = count($parts);
  2819.  
  2820.         $release = $machine = $cpu = '';
  2821.         $sysname = $parts[0];
  2822.         $nodename = $parts[1];
  2823.         $cpu = $parts[$n-1];
  2824.         $extra = '';
  2825.         if ($cpu == 'unknown') {
  2826.             $cpu = $parts[$n-2];
  2827.         }
  2828.  
  2829.         switch ($sysname) {
  2830.             case 'AIX' :
  2831.                 $release = "$parts[3].$parts[2]";
  2832.                 break;
  2833.             case 'Windows' :
  2834.                 switch ($parts[1]) {
  2835.                     case '95/98':
  2836.                         $release = '9x';
  2837.                         break;
  2838.                     default:
  2839.                         $release = $parts[1];
  2840.                         break;
  2841.                 }
  2842.                 $cpu = 'i386';
  2843.                 break;
  2844.             case 'Linux' :
  2845.                 $extra = $this->_detectGlibcVersion();
  2846.                 // use only the first two digits from the kernel version
  2847.                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
  2848.                 break;
  2849.             case 'Mac' :
  2850.                 $sysname = 'darwin';
  2851.                 $nodename = $parts[2];
  2852.                 $release = $parts[3];
  2853.                 if ($cpu == 'Macintosh') {
  2854.                     if ($parts[$n - 2] == 'Power') {
  2855.                         $cpu = 'powerpc';
  2856.                     }
  2857.                 }
  2858.                 break;
  2859.             case 'Darwin' :
  2860.                 if ($cpu == 'Macintosh') {
  2861.                     if ($parts[$n - 2] == 'Power') {
  2862.                         $cpu = 'powerpc';
  2863.                     }
  2864.                 }
  2865.                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
  2866.                 break;
  2867.             default:
  2868.                 $release = ereg_replace('-.*', '', $parts[2]);
  2869.                 break;
  2870.         }
  2871.  
  2872.  
  2873.         if (isset($sysmap[$sysname])) {
  2874.             $sysname = $sysmap[$sysname];
  2875.         } else {
  2876.             $sysname = strtolower($sysname);
  2877.         }
  2878.         if (isset($cpumap[$cpu])) {
  2879.             $cpu = $cpumap[$cpu];
  2880.         }
  2881.         return array($sysname, $release, $cpu, $extra, $nodename);
  2882.     }
  2883.  
  2884.     function _detectGlibcVersion()
  2885.     {
  2886.         static $glibc = false;
  2887.         if ($glibc !== false) {
  2888.             return $glibc; // no need to run this multiple times
  2889.         }
  2890.         include_once "phar://go-pear.phar/System.php";
  2891.         if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
  2892.             // Use glibc's <features.h> header file to
  2893.             // get major and minor version number:
  2894.             if (@file_exists('/usr/include/features.h') &&
  2895.                   @is_readable('/usr/include/features.h')) {
  2896.                 $features_file = fopen('/usr/include/features.h', 'rb');
  2897.                 while (!feof($features_file)) {
  2898.                     $line = fgets($features_file, 8192);
  2899.                     if (!$line || (strpos($line, '#define') === false)) {
  2900.                         continue;
  2901.                     }
  2902.                     if (strpos($line, '__GLIBC__')) {
  2903.                         // major version number #define __GLIBC__ version
  2904.                         $line = preg_split('/\s+/', $line);
  2905.                         $glibc_major = trim($line[2]);
  2906.                         if (isset($glibc_minor)) {
  2907.                             break;
  2908.                         }
  2909.                         continue;
  2910.                     }
  2911.                     if (strpos($line, '__GLIBC_MINOR__'))  {
  2912.                         // got the minor version number
  2913.                         // #define __GLIBC_MINOR__ version
  2914.                         $line = preg_split('/\s+/', $line);
  2915.                         $glibc_minor = trim($line[2]);
  2916.                         if (isset($glibc_major)) {
  2917.                             break;
  2918.                         }
  2919.                         continue;
  2920.                     }
  2921.                 }
  2922.                 fclose($features_file);
  2923.                 if (!isset($glibc_major) || !isset($glibc_minor)) {
  2924.                     return $glibc = '';
  2925.                 }
  2926.                 return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
  2927.             }
  2928.             return $glibc = '';
  2929.         }
  2930.         $tmpfile = System::mktemp("glibctest");
  2931.         $fp = fopen($tmpfile, "w");
  2932.         fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
  2933.         fclose($fp);
  2934.         $cpp = popen("/usr/bin/cpp $tmpfile", "r");
  2935.         $major = $minor = 0;
  2936.         while ($line = fgets($cpp, 1024)) {
  2937.             if ($line{0} == '#' || trim($line) == '') {
  2938.                 continue;
  2939.             }
  2940.             if (list($major, $minor) = explode(' ', trim($line))) {
  2941.                 break;
  2942.             }
  2943.         }
  2944.         pclose($cpp);
  2945.         unlink($tmpfile);
  2946.         if (!($major && $minor) && is_link('/lib/libc.so.6')) {
  2947.             // Let's try reading the libc.so.6 symlink
  2948.             if (ereg('^libc-([.*])\.so$', basename(readlink('/lib/libc.so.6')), $matches)) {
  2949.                 list($major, $minor) = explode('.', $matches);
  2950.             }
  2951.         }
  2952.         if (!($major && $minor)) {
  2953.             return $glibc = '';
  2954.         }
  2955.         return $glibc = "glibc{$major}.{$minor}";
  2956.     }
  2957.  
  2958.     function getSignature()
  2959.     {
  2960.         if (empty($this->extra)) {
  2961.             return "{$this->sysname}-{$this->release}-{$this->cpu}";
  2962.         }
  2963.         return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
  2964.     }
  2965.  
  2966.     function getSysname()
  2967.     {
  2968.         return $this->sysname;
  2969.     }
  2970.  
  2971.     function getNodename()
  2972.     {
  2973.         return $this->nodename;
  2974.     }
  2975.  
  2976.     function getCpu()
  2977.     {
  2978.         return $this->cpu;
  2979.     }
  2980.  
  2981.     function getRelease()
  2982.     {
  2983.         return $this->release;
  2984.     }
  2985.  
  2986.     function getExtra()
  2987.     {
  2988.         return $this->extra;
  2989.     }
  2990.  
  2991.     function matchSignature($match)
  2992.     {
  2993.         if (is_array($match)) {
  2994.             $fragments = $match;
  2995.         } else {
  2996.             $fragments = explode('-', $match);
  2997.         }
  2998.         $n = count($fragments);
  2999.         $matches = 0;
  3000.         if ($n > 0) {
  3001.             $matches += $this->_matchFragment($fragments[0], $this->sysname);
  3002.         }
  3003.         if ($n > 1) {
  3004.             $matches += $this->_matchFragment($fragments[1], $this->release);
  3005.         }
  3006.         if ($n > 2) {
  3007.             $matches += $this->_matchFragment($fragments[2], $this->cpu);
  3008.         }
  3009.         if ($n > 3) {
  3010.             $matches += $this->_matchFragment($fragments[3], $this->extra);
  3011.         }
  3012.         return ($matches == $n);
  3013.     }
  3014.  
  3015.     function _matchFragment($fragment, $value)
  3016.     {
  3017.         if (strcspn($fragment, '*?') < strlen($fragment)) {
  3018.             $reg = '^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '$';
  3019.             return eregi($reg, $value);
  3020.         }
  3021.         return ($fragment == '*' || !strcasecmp($fragment, $value));
  3022.     }
  3023.  
  3024. }
  3025. /*
  3026.  * Local Variables:
  3027.  * indent-tabs-mode: nil
  3028.  * c-basic-offset: 4
  3029.  * End:
  3030.  */
  3031. ?>
  3032. <?php
  3033. /**
  3034.  * PEAR, the PHP Extension and Application Repository
  3035.  *
  3036.  * PEAR class and PEAR_Error class
  3037.  *
  3038.  * PHP versions 4 and 5
  3039.  *
  3040.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  3041.  * that is available through the world-wide-web at the following URI:
  3042.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  3043.  * the PHP License and are unable to obtain it through the web, please
  3044.  * send a note to license@php.net so we can mail you a copy immediately.
  3045.  *
  3046.  * @category   pear
  3047.  * @package    PEAR
  3048.  * @author     Sterling Hughes <sterling@php.net>
  3049.  * @author     Stig Bakken <ssb@php.net>
  3050.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  3051.  * @author     Greg Beaver <cellog@php.net>
  3052.  * @copyright  1997-2006 The PHP Group
  3053.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  3054.  * @version    CVS: $Id: PEAR.php,v 1.101 2006/04/25 02:41:03 cellog Exp $
  3055.  * @link       http://pear.php.net/package/PEAR
  3056.  * @since      File available since Release 0.1
  3057.  */
  3058.  
  3059. /**#@+
  3060.  * ERROR constants
  3061.  */
  3062. define('PEAR_ERROR_RETURN',     1);
  3063. define('PEAR_ERROR_PRINT',      2);
  3064. define('PEAR_ERROR_TRIGGER',    4);
  3065. define('PEAR_ERROR_DIE',        8);
  3066. define('PEAR_ERROR_CALLBACK',  16);
  3067. /**
  3068.  * WARNING: obsolete
  3069.  * @deprecated
  3070.  */
  3071. define('PEAR_ERROR_EXCEPTION', 32);
  3072. /**#@-*/
  3073. define('PEAR_ZE2', (function_exists('version_compare') &&
  3074.                     version_compare(zend_version(), "2-dev", "ge")));
  3075.  
  3076. if (substr(PHP_OS, 0, 3) == 'WIN') {
  3077.     define('OS_WINDOWS', true);
  3078.     define('OS_UNIX',    false);
  3079.     define('PEAR_OS',    'Windows');
  3080. } else {
  3081.     define('OS_WINDOWS', false);
  3082.     define('OS_UNIX',    true);
  3083.     define('PEAR_OS',    'Unix'); // blatant assumption
  3084. }
  3085.  
  3086. // instant backwards compatibility
  3087. if (!defined('PATH_SEPARATOR')) {
  3088.     if (OS_WINDOWS) {
  3089.         define('PATH_SEPARATOR', ';');
  3090.     } else {
  3091.         define('PATH_SEPARATOR', ':');
  3092.     }
  3093. }
  3094.  
  3095. $GLOBALS['_PEAR_default_error_mode']     = PEAR_ERROR_RETURN;
  3096. $GLOBALS['_PEAR_default_error_options']  = E_USER_NOTICE;
  3097. $GLOBALS['_PEAR_destructor_object_list'] = array();
  3098. $GLOBALS['_PEAR_shutdown_funcs']         = array();
  3099. $GLOBALS['_PEAR_error_handler_stack']    = array();
  3100.  
  3101. @ini_set('track_errors', true);
  3102.  
  3103. /**
  3104.  * Base class for other PEAR classes.  Provides rudimentary
  3105.  * emulation of destructors.
  3106.  *
  3107.  * If you want a destructor in your class, inherit PEAR and make a
  3108.  * destructor method called _yourclassname (same name as the
  3109.  * constructor, but with a "_" prefix).  Also, in your constructor you
  3110.  * have to call the PEAR constructor: $this->PEAR();.
  3111.  * The destructor method will be called without parameters.  Note that
  3112.  * at in some SAPI implementations (such as Apache), any output during
  3113.  * the request shutdown (in which destructors are called) seems to be
  3114.  * discarded.  If you need to get any debug information from your
  3115.  * destructor, use error_log(), syslog() or something similar.
  3116.  *
  3117.  * IMPORTANT! To use the emulated destructors you need to create the
  3118.  * objects by reference: $obj =& new PEAR_child;
  3119.  *
  3120.  * @category   pear
  3121.  * @package    PEAR
  3122.  * @author     Stig Bakken <ssb@php.net>
  3123.  * @author     Tomas V.V. Cox <cox@idecnet.com>
  3124.  * @author     Greg Beaver <cellog@php.net>
  3125.  * @copyright  1997-2006 The PHP Group
  3126.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  3127.  * @version    Release: @package_version@
  3128.  * @link       http://pear.php.net/package/PEAR
  3129.  * @see        PEAR_Error
  3130.  * @since      Class available since PHP 4.0.2
  3131.  * @link        http://pear.php.net/manual/en/core.pear.php#core.pear.pear
  3132.  */
  3133. class PEAR
  3134. {
  3135.     // {{{ properties
  3136.  
  3137.     /**
  3138.      * Whether to enable internal debug messages.
  3139.      *
  3140.      * @var     bool
  3141.      * @access  private
  3142.      */
  3143.     var $_debug = false;
  3144.  
  3145.     /**
  3146.      * Default error mode for this object.
  3147.      *
  3148.      * @var     int
  3149.      * @access  private
  3150.      */
  3151.     var $_default_error_mode = null;
  3152.  
  3153.     /**
  3154.      * Default error options used for this object when error mode
  3155.      * is PEAR_ERROR_TRIGGER.
  3156.      *
  3157.      * @var     int
  3158.      * @access  private
  3159.      */
  3160.     var $_default_error_options = null;
  3161.  
  3162.     /**
  3163.      * Default error handler (callback) for this object, if error mode is
  3164.      * PEAR_ERROR_CALLBACK.
  3165.      *
  3166.      * @var     string
  3167.      * @access  private
  3168.      */
  3169.     var $_default_error_handler = '';
  3170.  
  3171.     /**
  3172.      * Which class to use for error objects.
  3173.      *
  3174.      * @var     string
  3175.      * @access  private
  3176.      */
  3177.     var $_error_class = 'PEAR_Error';
  3178.  
  3179.     /**
  3180.      * An array of expected errors.
  3181.      *
  3182.      * @var     array
  3183.      * @access  private
  3184.      */
  3185.     var $_expected_errors = array();
  3186.  
  3187.     // }}}
  3188.  
  3189.     // {{{ constructor
  3190.  
  3191.     /**
  3192.      * Constructor.  Registers this object in
  3193.      * $_PEAR_destructor_object_list for destructor emulation if a
  3194.      * destructor object exists.
  3195.      *
  3196.      * @param string $error_class  (optional) which class to use for
  3197.      *        error objects, defaults to PEAR_Error.
  3198.      * @access public
  3199.      * @return void
  3200.      */
  3201.     function PEAR($error_class = null)
  3202.     {
  3203.         $classname = strtolower(get_class($this));
  3204.         if ($this->_debug) {
  3205.             print "PEAR constructor called, class=$classname\n";
  3206.         }
  3207.         if ($error_class !== null) {
  3208.             $this->_error_class = $error_class;
  3209.         }
  3210.         while ($classname && strcasecmp($classname, "pear")) {
  3211.             $destructor = "_$classname";
  3212.             if (method_exists($this, $destructor)) {
  3213.                 global $_PEAR_destructor_object_list;
  3214.                 $_PEAR_destructor_object_list[] = &$this;
  3215.                 if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
  3216.                     register_shutdown_function("_PEAR_call_destructors");
  3217.                     $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
  3218.                 }
  3219.                 break;
  3220.             } else {
  3221.                 $classname = get_parent_class($classname);
  3222.             }
  3223.         }
  3224.     }
  3225.  
  3226.     // }}}
  3227.     // {{{ destructor
  3228.  
  3229.     /**
  3230.      * Destructor (the emulated type of...).  Does nothing right now,
  3231.      * but is included for forward compatibility, so subclass
  3232.      * destructors should always call it.
  3233.      *
  3234.      * See the note in the class desciption about output from
  3235.      * destructors.
  3236.      *
  3237.      * @access public
  3238.      * @return void
  3239.      */
  3240.     function _PEAR() {
  3241.         if ($this->_debug) {
  3242.             printf("PEAR destructor called, class=%s\n", strtolower(get_class($this)));
  3243.         }
  3244.     }
  3245.  
  3246.     // }}}
  3247.     // {{{ getStaticProperty()
  3248.  
  3249.     /**
  3250.     * If you have a class that's mostly/entirely static, and you need static
  3251.     * properties, you can use this method to simulate them. Eg. in your method(s)
  3252.     * do this: $myVar = &PEAR::getStaticProperty('myclass', 'myVar');
  3253.     * You MUST use a reference, or they will not persist!
  3254.     *
  3255.     * @access public
  3256.     * @param  string $class  The calling classname, to prevent clashes
  3257.     * @param  string $var    The variable to retrieve.
  3258.     * @return mixed   A reference to the variable. If not set it will be
  3259.     *                 auto initialised to NULL.
  3260.     */
  3261.     function &getStaticProperty($class, $var)
  3262.     {
  3263.         static $properties;
  3264.         if (!isset($properties[$class])) {
  3265.             $properties[$class] = array();
  3266.         }
  3267.         if (!array_key_exists($var, $properties[$class])) {
  3268.             $properties[$class][$var] = null;
  3269.         }
  3270.         return $properties[$class][$var];
  3271.     }
  3272.  
  3273.     // }}}
  3274.     // {{{ registerShutdownFunc()
  3275.  
  3276.     /**
  3277.     * Use this function to register a shutdown method for static
  3278.     * classes.
  3279.     *
  3280.     * @access public
  3281.     * @param  mixed $func  The function name (or array of class/method) to call
  3282.     * @param  mixed $args  The arguments to pass to the function
  3283.     * @return void
  3284.     */
  3285.     function registerShutdownFunc($func, $args = array())
  3286.     {
  3287.         // if we are called statically, there is a potential
  3288.         // that no shutdown func is registered.  Bug #6445
  3289.         if (!isset($GLOBALS['_PEAR_SHUTDOWN_REGISTERED'])) {
  3290.             register_shutdown_function("_PEAR_call_destructors");
  3291.             $GLOBALS['_PEAR_SHUTDOWN_REGISTERED'] = true;
  3292.         }
  3293.         $GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
  3294.     }
  3295.  
  3296.     // }}}
  3297.     // {{{ isError()
  3298.  
  3299.     /**
  3300.      * Tell whether a value is a PEAR error.
  3301.      *
  3302.      * @param   mixed $data   the value to test
  3303.      * @param   int   $code   if $data is an error object, return true
  3304.      *                        only if $code is a string and
  3305.      *                        $obj->getMessage() == $code or
  3306.      *                        $code is an integer and $obj->getCode() == $code
  3307.      * @access  public
  3308.      * @return  bool    true if parameter is an error
  3309.      */
  3310.     function isError($data, $code = null)
  3311.     {
  3312.         if (is_a($data, 'PEAR_Error')) {
  3313.             if (is_null($code)) {
  3314.                 return true;
  3315.             } elseif (is_string($code)) {
  3316.                 return $data->getMessage() == $code;
  3317.             } else {
  3318.                 return $data->getCode() == $code;
  3319.             }
  3320.         }
  3321.         return false;
  3322.     }
  3323.  
  3324.     // }}}
  3325.     // {{{ setErrorHandling()
  3326.  
  3327.     /**
  3328.      * Sets how errors generated by this object should be handled.
  3329.      * Can be invoked both in objects and statically.  If called
  3330.      * statically, setErrorHandling sets the default behaviour for all
  3331.      * PEAR objects.  If called in an object, setErrorHandling sets
  3332.      * the default behaviour for that object.
  3333.      *
  3334.      * @param int $mode
  3335.      *        One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  3336.      *        PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  3337.      *        PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION.
  3338.      *
  3339.      * @param mixed $options
  3340.      *        When $mode is PEAR_ERROR_TRIGGER, this is the error level (one
  3341.      *        of E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  3342.      *
  3343.      *        When $mode is PEAR_ERROR_CALLBACK, this parameter is expected
  3344.      *        to be the callback function or method.  A callback
  3345.      *        function is a string with the name of the function, a
  3346.      *        callback method is an array of two elements: the element
  3347.      *        at index 0 is the object, and the element at index 1 is
  3348.      *        the name of the method to call in the object.
  3349.      *
  3350.      *        When $mode is PEAR_ERROR_PRINT or PEAR_ERROR_DIE, this is
  3351.      *        a printf format string used when printing the error
  3352.      *        message.
  3353.      *
  3354.      * @access public
  3355.      * @return void
  3356.      * @see PEAR_ERROR_RETURN
  3357.      * @see PEAR_ERROR_PRINT
  3358.      * @see PEAR_ERROR_TRIGGER
  3359.      * @see PEAR_ERROR_DIE
  3360.      * @see PEAR_ERROR_CALLBACK
  3361.      * @see PEAR_ERROR_EXCEPTION
  3362.      *
  3363.      * @since PHP 4.0.5
  3364.      */
  3365.  
  3366.     function setErrorHandling($mode = null, $options = null)
  3367.     {
  3368.         if (isset($this) && is_a($this, 'PEAR')) {
  3369.             $setmode     = &$this->_default_error_mode;
  3370.             $setoptions  = &$this->_default_error_options;
  3371.         } else {
  3372.             $setmode     = &$GLOBALS['_PEAR_default_error_mode'];
  3373.             $setoptions  = &$GLOBALS['_PEAR_default_error_options'];
  3374.         }
  3375.  
  3376.         switch ($mode) {
  3377.             case PEAR_ERROR_EXCEPTION:
  3378.             case PEAR_ERROR_RETURN:
  3379.             case PEAR_ERROR_PRINT:
  3380.             case PEAR_ERROR_TRIGGER:
  3381.             case PEAR_ERROR_DIE:
  3382.             case null:
  3383.                 $setmode = $mode;
  3384.                 $setoptions = $options;
  3385.                 break;
  3386.  
  3387.             case PEAR_ERROR_CALLBACK:
  3388.                 $setmode = $mode;
  3389.                 // class/object method callback
  3390.                 if (is_callable($options)) {
  3391.                     $setoptions = $options;
  3392.                 } else {
  3393.                     trigger_error("invalid error callback", E_USER_WARNING);
  3394.                 }
  3395.                 break;
  3396.  
  3397.             default:
  3398.                 trigger_error("invalid error mode", E_USER_WARNING);
  3399.                 break;
  3400.         }
  3401.     }
  3402.  
  3403.     // }}}
  3404.     // {{{ expectError()
  3405.  
  3406.     /**
  3407.      * This method is used to tell which errors you expect to get.
  3408.      * Expected errors are always returned with error mode
  3409.      * PEAR_ERROR_RETURN.  Expected error codes are stored in a stack,
  3410.      * and this method pushes a new element onto it.  The list of
  3411.      * expected errors are in effect until they are popped off the
  3412.      * stack with the popExpect() method.
  3413.      *
  3414.      * Note that this method can not be called statically
  3415.      *
  3416.      * @param mixed $code a single error code or an array of error codes to expect
  3417.      *
  3418.      * @return int     the new depth of the "expected errors" stack
  3419.      * @access public
  3420.      */
  3421.     function expectError($code = '*')
  3422.     {
  3423.         if (is_array($code)) {
  3424.             array_push($this->_expected_errors, $code);
  3425.         } else {
  3426.             array_push($this->_expected_errors, array($code));
  3427.         }
  3428.         return sizeof($this->_expected_errors);
  3429.     }
  3430.  
  3431.     // }}}
  3432.     // {{{ popExpect()
  3433.  
  3434.     /**
  3435.      * This method pops one element off the expected error codes
  3436.      * stack.
  3437.      *
  3438.      * @return array   the list of error codes that were popped
  3439.      */
  3440.     function popExpect()
  3441.     {
  3442.         return array_pop($this->_expected_errors);
  3443.     }
  3444.  
  3445.     // }}}
  3446.     // {{{ _checkDelExpect()
  3447.  
  3448.     /**
  3449.      * This method checks unsets an error code if available
  3450.      *
  3451.      * @param mixed error code
  3452.      * @return bool true if the error code was unset, false otherwise
  3453.      * @access private
  3454.      * @since PHP 4.3.0
  3455.      */
  3456.     function _checkDelExpect($error_code)
  3457.     {
  3458.         $deleted = false;
  3459.  
  3460.         foreach ($this->_expected_errors AS $key => $error_array) {
  3461.             if (in_array($error_code, $error_array)) {
  3462.                 unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
  3463.                 $deleted = true;
  3464.             }
  3465.  
  3466.             // clean up empty arrays
  3467.             if (0 == count($this->_expected_errors[$key])) {
  3468.                 unset($this->_expected_errors[$key]);
  3469.             }
  3470.         }
  3471.         return $deleted;
  3472.     }
  3473.  
  3474.     // }}}
  3475.     // {{{ delExpect()
  3476.  
  3477.     /**
  3478.      * This method deletes all occurences of the specified element from
  3479.      * the expected error codes stack.
  3480.      *
  3481.      * @param  mixed $error_code error code that should be deleted
  3482.      * @return mixed list of error codes that were deleted or error
  3483.      * @access public
  3484.      * @since PHP 4.3.0
  3485.      */
  3486.     function delExpect($error_code)
  3487.     {
  3488.         $deleted = false;
  3489.  
  3490.         if ((is_array($error_code) && (0 != count($error_code)))) {
  3491.             // $error_code is a non-empty array here;
  3492.             // we walk through it trying to unset all
  3493.             // values
  3494.             foreach($error_code as $key => $error) {
  3495.                 if ($this->_checkDelExpect($error)) {
  3496.                     $deleted =  true;
  3497.                 } else {
  3498.                     $deleted = false;
  3499.                 }
  3500.             }
  3501.             return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
  3502.         } elseif (!empty($error_code)) {
  3503.             // $error_code comes alone, trying to unset it
  3504.             if ($this->_checkDelExpect($error_code)) {
  3505.                 return true;
  3506.             } else {
  3507.                 return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
  3508.             }
  3509.         } else {
  3510.             // $error_code is empty
  3511.             return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
  3512.         }
  3513.     }
  3514.  
  3515.     // }}}
  3516.     // {{{ raiseError()
  3517.  
  3518.     /**
  3519.      * This method is a wrapper that returns an instance of the
  3520.      * configured error class with this object's default error
  3521.      * handling applied.  If the $mode and $options parameters are not
  3522.      * specified, the object's defaults are used.
  3523.      *
  3524.      * @param mixed $message a text error message or a PEAR error object
  3525.      *
  3526.      * @param int $code      a numeric error code (it is up to your class
  3527.      *                  to define these if you want to use codes)
  3528.      *
  3529.      * @param int $mode      One of PEAR_ERROR_RETURN, PEAR_ERROR_PRINT,
  3530.      *                  PEAR_ERROR_TRIGGER, PEAR_ERROR_DIE,
  3531.      *                  PEAR_ERROR_CALLBACK, PEAR_ERROR_EXCEPTION.
  3532.      *
  3533.      * @param mixed $options If $mode is PEAR_ERROR_TRIGGER, this parameter
  3534.      *                  specifies the PHP-internal error level (one of
  3535.      *                  E_USER_NOTICE, E_USER_WARNING or E_USER_ERROR).
  3536.      *                  If $mode is PEAR_ERROR_CALLBACK, this
  3537.      *                  parameter specifies the callback function or
  3538.      *                  method.  In other error modes this parameter
  3539.      *                  is ignored.
  3540.      *
  3541.      * @param string $userinfo If you need to pass along for example debug
  3542.      *                  information, this parameter is meant for that.
  3543.      *
  3544.      * @param string $error_class The returned error object will be
  3545.      *                  instantiated from this class, if specified.
  3546.      *
  3547.      * @param bool $skipmsg If true, raiseError will only pass error codes,
  3548.      *                  the error message parameter will be dropped.
  3549.      *
  3550.      * @access public
  3551.      * @return object   a PEAR error object
  3552.      * @see PEAR::setErrorHandling
  3553.      * @since PHP 4.0.5
  3554.      */
  3555.     function &raiseError($message = null,
  3556.                          $code = null,
  3557.                          $mode = null,
  3558.                          $options = null,
  3559.                          $userinfo = null,
  3560.                          $error_class = null,
  3561.                          $skipmsg = false)
  3562.     {
  3563.         // The error is yet a PEAR error object
  3564.         if (is_object($message)) {
  3565.             $code        = $message->getCode();
  3566.             $userinfo    = $message->getUserInfo();
  3567.             $error_class = $message->getType();
  3568.             $message->error_message_prefix = '';
  3569.             $message     = $message->getMessage();
  3570.         }
  3571.  
  3572.         if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {
  3573.             if ($exp[0] == "*" ||
  3574.                 (is_int(reset($exp)) && in_array($code, $exp)) ||
  3575.                 (is_string(reset($exp)) && in_array($message, $exp))) {
  3576.                 $mode = PEAR_ERROR_RETURN;
  3577.             }
  3578.         }
  3579.         // No mode given, try global ones
  3580.         if ($mode === null) {
  3581.             // Class error handler
  3582.             if (isset($this) && isset($this->_default_error_mode)) {
  3583.                 $mode    = $this->_default_error_mode;
  3584.                 $options = $this->_default_error_options;
  3585.             // Global error handler
  3586.             } elseif (isset($GLOBALS['_PEAR_default_error_mode'])) {
  3587.                 $mode    = $GLOBALS['_PEAR_default_error_mode'];
  3588.                 $options = $GLOBALS['_PEAR_default_error_options'];
  3589.             }
  3590.         }
  3591.  
  3592.         if ($error_class !== null) {
  3593.             $ec = $error_class;
  3594.         } elseif (isset($this) && isset($this->_error_class)) {
  3595.             $ec = $this->_error_class;
  3596.         } else {
  3597.             $ec = 'PEAR_Error';
  3598.         }
  3599.         if ($skipmsg) {
  3600.             $a = &new $ec($code, $mode, $options, $userinfo);
  3601.             return $a;
  3602.         } else {
  3603.             $a = &new $ec($message, $code, $mode, $options, $userinfo);
  3604.             return $a;
  3605.         }
  3606.     }
  3607.  
  3608.     // }}}
  3609.     // {{{ throwError()
  3610.  
  3611.     /**
  3612.      * Simpler form of raiseError with fewer options.  In most cases
  3613.      * message, code and userinfo are enough.
  3614.      *
  3615.      * @param string $message
  3616.      *
  3617.      */
  3618.     function &throwError($message = null,
  3619.                          $code = null,
  3620.                          $userinfo = null)
  3621.     {
  3622.         if (isset($this) && is_a($this, 'PEAR')) {
  3623.             $a = &$this->raiseError($message, $code, null, null, $userinfo);
  3624.             return $a;
  3625.         } else {
  3626.             $a = &PEAR::raiseError($message, $code, null, null, $userinfo);
  3627.             return $a;
  3628.         }
  3629.     }
  3630.  
  3631.     // }}}
  3632.     function staticPushErrorHandling($mode, $options = null)
  3633.     {
  3634.         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  3635.         $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
  3636.         $def_options = &$GLOBALS['_PEAR_default_error_options'];
  3637.         $stack[] = array($def_mode, $def_options);
  3638.         switch ($mode) {
  3639.             case PEAR_ERROR_EXCEPTION:
  3640.             case PEAR_ERROR_RETURN:
  3641.             case PEAR_ERROR_PRINT:
  3642.             case PEAR_ERROR_TRIGGER:
  3643.             case PEAR_ERROR_DIE:
  3644.             case null:
  3645.                 $def_mode = $mode;
  3646.                 $def_options = $options;
  3647.                 break;
  3648.  
  3649.             case PEAR_ERROR_CALLBACK:
  3650.                 $def_mode = $mode;
  3651.                 // class/object method callback
  3652.                 if (is_callable($options)) {
  3653.                     $def_options = $options;
  3654.                 } else {
  3655.                     trigger_error("invalid error callback", E_USER_WARNING);
  3656.                 }
  3657.                 break;
  3658.  
  3659.             default:
  3660.                 trigger_error("invalid error mode", E_USER_WARNING);
  3661.                 break;
  3662.         }
  3663.         $stack[] = array($mode, $options);
  3664.         return true;
  3665.     }
  3666.  
  3667.     function staticPopErrorHandling()
  3668.     {
  3669.         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  3670.         $setmode     = &$GLOBALS['_PEAR_default_error_mode'];
  3671.         $setoptions  = &$GLOBALS['_PEAR_default_error_options'];
  3672.         array_pop($stack);
  3673.         list($mode, $options) = $stack[sizeof($stack) - 1];
  3674.         array_pop($stack);
  3675.         switch ($mode) {
  3676.             case PEAR_ERROR_EXCEPTION:
  3677.             case PEAR_ERROR_RETURN:
  3678.             case PEAR_ERROR_PRINT:
  3679.             case PEAR_ERROR_TRIGGER:
  3680.             case PEAR_ERROR_DIE:
  3681.             case null:
  3682.                 $setmode = $mode;
  3683.                 $setoptions = $options;
  3684.                 break;
  3685.  
  3686.             case PEAR_ERROR_CALLBACK:
  3687.                 $setmode = $mode;
  3688.                 // class/object method callback
  3689.                 if (is_callable($options)) {
  3690.                     $setoptions = $options;
  3691.                 } else {
  3692.                     trigger_error("invalid error callback", E_USER_WARNING);
  3693.                 }
  3694.                 break;
  3695.  
  3696.             default:
  3697.                 trigger_error("invalid error mode", E_USER_WARNING);
  3698.                 break;
  3699.         }
  3700.         return true;
  3701.     }
  3702.  
  3703.     // {{{ pushErrorHandling()
  3704.  
  3705.     /**
  3706.      * Push a new error handler on top of the error handler options stack. With this
  3707.      * you can easily override the actual error handler for some code and restore
  3708.      * it later with popErrorHandling.
  3709.      *
  3710.      * @param mixed $mode (same as setErrorHandling)
  3711.      * @param mixed $options (same as setErrorHandling)
  3712.      *
  3713.      * @return bool Always true
  3714.      *
  3715.      * @see PEAR::setErrorHandling
  3716.      */
  3717.     function pushErrorHandling($mode, $options = null)
  3718.     {
  3719.         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  3720.         if (isset($this) && is_a($this, 'PEAR')) {
  3721.             $def_mode    = &$this->_default_error_mode;
  3722.             $def_options = &$this->_default_error_options;
  3723.         } else {
  3724.             $def_mode    = &$GLOBALS['_PEAR_default_error_mode'];
  3725.             $def_options = &$GLOBALS['_PEAR_default_error_options'];
  3726.         }
  3727.         $stack[] = array($def_mode, $def_options);
  3728.  
  3729.         if (isset($this) && is_a($this, 'PEAR')) {
  3730.             $this->setErrorHandling($mode, $options);
  3731.         } else {
  3732.             PEAR::setErrorHandling($mode, $options);
  3733.         }
  3734.         $stack[] = array($mode, $options);
  3735.         return true;
  3736.     }
  3737.  
  3738.     // }}}
  3739.     // {{{ popErrorHandling()
  3740.  
  3741.     /**
  3742.     * Pop the last error handler used
  3743.     *
  3744.     * @return bool Always true
  3745.     *
  3746.     * @see PEAR::pushErrorHandling
  3747.     */
  3748.     function popErrorHandling()
  3749.     {
  3750.         $stack = &$GLOBALS['_PEAR_error_handler_stack'];
  3751.         array_pop($stack);
  3752.         list($mode, $options) = $stack[sizeof($stack) - 1];
  3753.         array_pop($stack);
  3754.         if (isset($this) && is_a($this, 'PEAR')) {
  3755.             $this->setErrorHandling($mode, $options);
  3756.         } else {
  3757.             PEAR::setErrorHandling($mode, $options);
  3758.         }
  3759.         return true;
  3760.     }
  3761.  
  3762.     // }}}
  3763.     // {{{ loadExtension()
  3764.  
  3765.     /**
  3766.     * OS independant PHP extension load. Remember to take care
  3767.     * on the correct extension name for case sensitive OSes.
  3768.     *
  3769.     * @param string $ext The extension name
  3770.     * @return bool Success or not on the dl() call
  3771.     */
  3772.     function loadExtension($ext)
  3773.     {
  3774.         if (!extension_loaded($ext)) {
  3775.             // if either returns true dl() will produce a FATAL error, stop that
  3776.             if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
  3777.                 return false;
  3778.             }
  3779.             if (OS_WINDOWS) {
  3780.                 $suffix = '.dll';
  3781.             } elseif (PHP_OS == 'HP-UX') {
  3782.                 $suffix = '.sl';
  3783.             } elseif (PHP_OS == 'AIX') {
  3784.                 $suffix = '.a';
  3785.             } elseif (PHP_OS == 'OSX') {
  3786.                 $suffix = '.bundle';
  3787.             } else {
  3788.                 $suffix = '.so';
  3789.             }
  3790.             return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
  3791.         }
  3792.         return true;
  3793.     }
  3794.  
  3795.     // }}}
  3796. }
  3797.  
  3798. // {{{ _PEAR_call_destructors()
  3799.  
  3800. function _PEAR_call_destructors()
  3801. {
  3802.     global $_PEAR_destructor_object_list;
  3803.     if (is_array($_PEAR_destructor_object_list) &&
  3804.         sizeof($_PEAR_destructor_object_list))
  3805.     {
  3806.         reset($_PEAR_destructor_object_list);
  3807.         if (PEAR::getStaticProperty('PEAR', 'destructlifo')) {
  3808.             $_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
  3809.         }
  3810.         while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
  3811.             $classname = get_class($objref);
  3812.             while ($classname) {
  3813.                 $destructor = "_$classname";
  3814.                 if (method_exists($objref, $destructor)) {
  3815.                     $objref->$destructor();
  3816.                     break;
  3817.                 } else {
  3818.                     $classname = get_parent_class($classname);
  3819.                 }
  3820.             }
  3821.         }
  3822.         // Empty the object list to ensure that destructors are
  3823.         // not called more than once.
  3824.         $_PEAR_destructor_object_list = array();
  3825.     }
  3826.  
  3827.     // Now call the shutdown functions
  3828.     if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
  3829.         foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
  3830.             call_user_func_array($value[0], $value[1]);
  3831.         }
  3832.     }
  3833. }
  3834.  
  3835. // }}}
  3836. /**
  3837.  * Standard PEAR error class for PHP 4
  3838.  *
  3839.  * This class is supserseded by {@link PEAR_Exception} in PHP 5
  3840.  *
  3841.  * @category   pear
  3842.  * @package    PEAR
  3843.  * @author     Stig Bakken <ssb@php.net>
  3844.  * @author     Tomas V.V. Cox <cox@idecnet.com>
  3845.  * @author     Gregory Beaver <cellog@php.net>
  3846.  * @copyright  1997-2006 The PHP Group
  3847.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  3848.  * @version    Release: @package_version@
  3849.  * @link       http://pear.php.net/manual/en/core.pear.pear-error.php
  3850.  * @see        PEAR::raiseError(), PEAR::throwError()
  3851.  * @since      Class available since PHP 4.0.2
  3852.  */
  3853. class PEAR_Error
  3854. {
  3855.     // {{{ properties
  3856.  
  3857.     var $error_message_prefix = '';
  3858.     var $mode                 = PEAR_ERROR_RETURN;
  3859.     var $level                = E_USER_NOTICE;
  3860.     var $code                 = -1;
  3861.     var $message              = '';
  3862.     var $userinfo             = '';
  3863.     var $backtrace            = null;
  3864.  
  3865.     // }}}
  3866.     // {{{ constructor
  3867.  
  3868.     /**
  3869.      * PEAR_Error constructor
  3870.      *
  3871.      * @param string $message  message
  3872.      *
  3873.      * @param int $code     (optional) error code
  3874.      *
  3875.      * @param int $mode     (optional) error mode, one of: PEAR_ERROR_RETURN,
  3876.      * PEAR_ERROR_PRINT, PEAR_ERROR_DIE, PEAR_ERROR_TRIGGER,
  3877.      * PEAR_ERROR_CALLBACK or PEAR_ERROR_EXCEPTION
  3878.      *
  3879.      * @param mixed $options   (optional) error level, _OR_ in the case of
  3880.      * PEAR_ERROR_CALLBACK, the callback function or object/method
  3881.      * tuple.
  3882.      *
  3883.      * @param string $userinfo (optional) additional user/debug info
  3884.      *
  3885.      * @access public
  3886.      *
  3887.      */
  3888.     function PEAR_Error($message = 'unknown error', $code = null,
  3889.                         $mode = null, $options = null, $userinfo = null)
  3890.     {
  3891.         if ($mode === null) {
  3892.             $mode = PEAR_ERROR_RETURN;
  3893.         }
  3894.         $this->message   = $message;
  3895.         $this->code      = $code;
  3896.         $this->mode      = $mode;
  3897.         $this->userinfo  = $userinfo;
  3898.         if (!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) {
  3899.             $this->backtrace = debug_backtrace();
  3900.             if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
  3901.                 unset($this->backtrace[0]['object']);
  3902.             }
  3903.         }
  3904.         if ($mode & PEAR_ERROR_CALLBACK) {
  3905.             $this->level = E_USER_NOTICE;
  3906.             $this->callback = $options;
  3907.         } else {
  3908.             if ($options === null) {
  3909.                 $options = E_USER_NOTICE;
  3910.             }
  3911.             $this->level = $options;
  3912.             $this->callback = null;
  3913.         }
  3914.         if ($this->mode & PEAR_ERROR_PRINT) {
  3915.             if (is_null($options) || is_int($options)) {
  3916.                 $format = "%s";
  3917.             } else {
  3918.                 $format = $options;
  3919.             }
  3920.             printf($format, $this->getMessage());
  3921.         }
  3922.         if ($this->mode & PEAR_ERROR_TRIGGER) {
  3923.             trigger_error($this->getMessage(), $this->level);
  3924.         }
  3925.         if ($this->mode & PEAR_ERROR_DIE) {
  3926.             $msg = $this->getMessage();
  3927.             if (is_null($options) || is_int($options)) {
  3928.                 $format = "%s";
  3929.                 if (substr($msg, -1) != "\n") {
  3930.                     $msg .= "\n";
  3931.                 }
  3932.             } else {
  3933.                 $format = $options;
  3934.             }
  3935.             die(sprintf($format, $msg));
  3936.         }
  3937.         if ($this->mode & PEAR_ERROR_CALLBACK) {
  3938.             if (is_callable($this->callback)) {
  3939.                 call_user_func($this->callback, $this);
  3940.             }
  3941.         }
  3942.         if ($this->mode & PEAR_ERROR_EXCEPTION) {
  3943.             trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
  3944.             eval('$e = new Exception($this->message, $this->code);throw($e);');
  3945.         }
  3946.     }
  3947.  
  3948.     // }}}
  3949.     // {{{ getMode()
  3950.  
  3951.     /**
  3952.      * Get the error mode from an error object.
  3953.      *
  3954.      * @return int error mode
  3955.      * @access public
  3956.      */
  3957.     function getMode() {
  3958.         return $this->mode;
  3959.     }
  3960.  
  3961.     // }}}
  3962.     // {{{ getCallback()
  3963.  
  3964.     /**
  3965.      * Get the callback function/method from an error object.
  3966.      *
  3967.      * @return mixed callback function or object/method array
  3968.      * @access public
  3969.      */
  3970.     function getCallback() {
  3971.         return $this->callback;
  3972.     }
  3973.  
  3974.     // }}}
  3975.     // {{{ getMessage()
  3976.  
  3977.  
  3978.     /**
  3979.      * Get the error message from an error object.
  3980.      *
  3981.      * @return  string  full error message
  3982.      * @access public
  3983.      */
  3984.     function getMessage()
  3985.     {
  3986.         return ($this->error_message_prefix . $this->message);
  3987.     }
  3988.  
  3989.  
  3990.     // }}}
  3991.     // {{{ getCode()
  3992.  
  3993.     /**
  3994.      * Get error code from an error object
  3995.      *
  3996.      * @return int error code
  3997.      * @access public
  3998.      */
  3999.      function getCode()
  4000.      {
  4001.         return $this->code;
  4002.      }
  4003.  
  4004.     // }}}
  4005.     // {{{ getType()
  4006.  
  4007.     /**
  4008.      * Get the name of this error/exception.
  4009.      *
  4010.      * @return string error/exception name (type)
  4011.      * @access public
  4012.      */
  4013.     function getType()
  4014.     {
  4015.         return get_class($this);
  4016.     }
  4017.  
  4018.     // }}}
  4019.     // {{{ getUserInfo()
  4020.  
  4021.     /**
  4022.      * Get additional user-supplied information.
  4023.      *
  4024.      * @return string user-supplied information
  4025.      * @access public
  4026.      */
  4027.     function getUserInfo()
  4028.     {
  4029.         return $this->userinfo;
  4030.     }
  4031.  
  4032.     // }}}
  4033.     // {{{ getDebugInfo()
  4034.  
  4035.     /**
  4036.      * Get additional debug information supplied by the application.
  4037.      *
  4038.      * @return string debug information
  4039.      * @access public
  4040.      */
  4041.     function getDebugInfo()
  4042.     {
  4043.         return $this->getUserInfo();
  4044.     }
  4045.  
  4046.     // }}}
  4047.     // {{{ getBacktrace()
  4048.  
  4049.     /**
  4050.      * Get the call backtrace from where the error was generated.
  4051.      * Supported with PHP 4.3.0 or newer.
  4052.      *
  4053.      * @param int $frame (optional) what frame to fetch
  4054.      * @return array Backtrace, or NULL if not available.
  4055.      * @access public
  4056.      */
  4057.     function getBacktrace($frame = null)
  4058.     {
  4059.         if (defined('PEAR_IGNORE_BACKTRACE')) {
  4060.             return null;
  4061.         }
  4062.         if ($frame === null) {
  4063.             return $this->backtrace;
  4064.         }
  4065.         return $this->backtrace[$frame];
  4066.     }
  4067.  
  4068.     // }}}
  4069.     // {{{ addUserInfo()
  4070.  
  4071.     function addUserInfo($info)
  4072.     {
  4073.         if (empty($this->userinfo)) {
  4074.             $this->userinfo = $info;
  4075.         } else {
  4076.             $this->userinfo .= " ** $info";
  4077.         }
  4078.     }
  4079.  
  4080.     // }}}
  4081.     // {{{ toString()
  4082.  
  4083.     /**
  4084.      * Make a string representation of this object.
  4085.      *
  4086.      * @return string a string with an object summary
  4087.      * @access public
  4088.      */
  4089.     function toString() {
  4090.         $modes = array();
  4091.         $levels = array(E_USER_NOTICE  => 'notice',
  4092.                         E_USER_WARNING => 'warning',
  4093.                         E_USER_ERROR   => 'error');
  4094.         if ($this->mode & PEAR_ERROR_CALLBACK) {
  4095.             if (is_array($this->callback)) {
  4096.                 $callback = (is_object($this->callback[0]) ?
  4097.                     strtolower(get_class($this->callback[0])) :
  4098.                     $this->callback[0]) . '::' .
  4099.                     $this->callback[1];
  4100.             } else {
  4101.                 $callback = $this->callback;
  4102.             }
  4103.             return sprintf('[%s: message="%s" code=%d mode=callback '.
  4104.                            'callback=%s prefix="%s" info="%s"]',
  4105.                            strtolower(get_class($this)), $this->message, $this->code,
  4106.                            $callback, $this->error_message_prefix,
  4107.                            $this->userinfo);
  4108.         }
  4109.         if ($this->mode & PEAR_ERROR_PRINT) {
  4110.             $modes[] = 'print';
  4111.         }
  4112.         if ($this->mode & PEAR_ERROR_TRIGGER) {
  4113.             $modes[] = 'trigger';
  4114.         }
  4115.         if ($this->mode & PEAR_ERROR_DIE) {
  4116.             $modes[] = 'die';
  4117.         }
  4118.         if ($this->mode & PEAR_ERROR_RETURN) {
  4119.             $modes[] = 'return';
  4120.         }
  4121.         return sprintf('[%s: message="%s" code=%d mode=%s level=%s '.
  4122.                        'prefix="%s" info="%s"]',
  4123.                        strtolower(get_class($this)), $this->message, $this->code,
  4124.                        implode("|", $modes), $levels[$this->level],
  4125.                        $this->error_message_prefix,
  4126.                        $this->userinfo);
  4127.     }
  4128.  
  4129.     // }}}
  4130. }
  4131.  
  4132. /*
  4133.  * Local Variables:
  4134.  * mode: php
  4135.  * tab-width: 4
  4136.  * c-basic-offset: 4
  4137.  * End:
  4138.  */
  4139. ?>
  4140. <?php
  4141. /**
  4142.  * PEAR_ChannelFile, the channel handling class
  4143.  *
  4144.  * PHP versions 4 and 5
  4145.  *
  4146.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  4147.  * that is available through the world-wide-web at the following URI:
  4148.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  4149.  * the PHP License and are unable to obtain it through the web, please
  4150.  * send a note to license@php.net so we can mail you a copy immediately.
  4151.  *
  4152.  * @category   pear
  4153.  * @package    PEAR
  4154.  * @author     Greg Beaver <cellog@php.net>
  4155.  * @copyright  1997-2006 The PHP Group
  4156.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  4157.  * @version    CVS: $Id: ChannelFile.php,v 1.77 2006/03/25 21:09:08 cellog Exp $
  4158.  * @link       http://pear.php.net/package/PEAR
  4159.  * @since      File available since Release 1.4.0a1
  4160.  */
  4161.  
  4162. /**
  4163.  * Needed for error handling
  4164.  */
  4165. require_once 'phar://go-pear.phar/PEAR/ErrorStack.php';
  4166. require_once 'phar://go-pear.phar/PEAR/XMLParser.php';
  4167. require_once 'phar://go-pear.phar/PEAR/Common.php';
  4168.  
  4169. /**
  4170.  * Error code if the channel.xml <channel> tag does not contain a valid version
  4171.  */
  4172. define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
  4173. /**
  4174.  * Error code if the channel.xml <channel> tag version is not supported (version 1.0 is the only supported version,
  4175.  * currently
  4176.  */
  4177. define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
  4178.  
  4179. /**
  4180.  * Error code if parsing is attempted with no xml extension
  4181.  */
  4182. define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
  4183.  
  4184. /**
  4185.  * Error code if creating the xml parser resource fails
  4186.  */
  4187. define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
  4188.  
  4189. /**
  4190.  * Error code used for all sax xml parsing errors
  4191.  */
  4192. define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
  4193.  
  4194. /**#@+
  4195.  * Validation errors
  4196.  */
  4197. /**
  4198.  * Error code when channel name is missing
  4199.  */
  4200. define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
  4201. /**
  4202.  * Error code when channel name is invalid
  4203.  */
  4204. define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
  4205. /**
  4206.  * Error code when channel summary is missing
  4207.  */
  4208. define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
  4209. /**
  4210.  * Error code when channel summary is multi-line
  4211.  */
  4212. define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
  4213. /**
  4214.  * Error code when channel server is missing for xmlrpc or soap protocol
  4215.  */
  4216. define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
  4217. /**
  4218.  * Error code when channel server is invalid for xmlrpc or soap protocol
  4219.  */
  4220. define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
  4221. /**
  4222.  * Error code when a mirror name is invalid
  4223.  */
  4224. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
  4225. /**
  4226.  * Error code when a mirror type is invalid
  4227.  */
  4228. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
  4229. /**
  4230.  * Error code when an attempt is made to generate xml, but the parsed content is invalid
  4231.  */
  4232. define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
  4233. /**
  4234.  * Error code when an empty package name validate regex is passed in
  4235.  */
  4236. define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
  4237. /**
  4238.  * Error code when a <function> tag has no version
  4239.  */
  4240. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
  4241. /**
  4242.  * Error code when a <function> tag has no name
  4243.  */
  4244. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
  4245. /**
  4246.  * Error code when a <validatepackage> tag has no name
  4247.  */
  4248. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
  4249. /**
  4250.  * Error code when a <validatepackage> tag has no version attribute
  4251.  */
  4252. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
  4253. /**
  4254.  * Error code when a mirror does not exist but is called for in one of the set*
  4255.  * methods.
  4256.  */
  4257. define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
  4258. /**
  4259.  * Error code when a server port is not numeric
  4260.  */
  4261. define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
  4262. /**
  4263.  * Error code when <static> contains no version attribute
  4264.  */
  4265. define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
  4266. /**
  4267.  * Error code when <baseurl> contains no type attribute in a <rest> protocol definition
  4268.  */
  4269. define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
  4270. /** 
  4271.  * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
  4272.  */
  4273. define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
  4274. /** 
  4275.  * Error code when ssl attribute is present and is not "yes"
  4276.  */
  4277. define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
  4278. /**#@-*/
  4279.  
  4280. /**
  4281.  * Mirror types allowed.  Currently only internet servers are recognized.
  4282.  */
  4283. $GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] =  array('server');
  4284.  
  4285.  
  4286. /**
  4287.  * The Channel handling class
  4288.  *
  4289.  * @category   pear
  4290.  * @package    PEAR
  4291.  * @author     Greg Beaver <cellog@php.net>
  4292.  * @copyright  1997-2006 The PHP Group
  4293.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  4294.  * @version    Release: @package_version@
  4295.  * @link       http://pear.php.net/package/PEAR
  4296.  * @since      Class available since Release 1.4.0a1
  4297.  */
  4298. class PEAR_ChannelFile {
  4299.     /**
  4300.      * @access private
  4301.      * @var PEAR_ErrorStack
  4302.      * @access private
  4303.      */
  4304.     var $_stack;
  4305.     
  4306.     /**
  4307.      * Supported channel.xml versions, for parsing
  4308.      * @var array
  4309.      * @access private
  4310.      */
  4311.     var $_supportedVersions = array('1.0');
  4312.  
  4313.     /**
  4314.      * Parsed channel information
  4315.      * @var array
  4316.      * @access private
  4317.      */
  4318.     var $_channelInfo;
  4319.  
  4320.     /**
  4321.      * index into the subchannels array, used for parsing xml
  4322.      * @var int
  4323.      * @access private
  4324.      */
  4325.     var $_subchannelIndex;
  4326.  
  4327.     /**
  4328.      * index into the mirrors array, used for parsing xml
  4329.      * @var int
  4330.      * @access private
  4331.      */
  4332.     var $_mirrorIndex;
  4333.     
  4334.     /**
  4335.      * Flag used to determine the validity of parsed content
  4336.      * @var boolean
  4337.      * @access private
  4338.      */
  4339.     var $_isValid = false;
  4340.  
  4341.     function PEAR_ChannelFile()
  4342.     {
  4343.         $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile');
  4344.         $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
  4345.         $this->_isValid = false;
  4346.     }
  4347.     
  4348.     /**
  4349.      * @return array
  4350.      * @access protected
  4351.      */
  4352.     function _getErrorMessage()
  4353.     {
  4354.         return
  4355.             array(
  4356.                 PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
  4357.                     'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
  4358.                 PEAR_CHANNELFILE_ERROR_NO_VERSION =>
  4359.                     'No version number found in <channel> tag',
  4360.                 PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
  4361.                     '%error%',
  4362.                 PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
  4363.                     'Unable to create XML parser',
  4364.                 PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
  4365.                     '%error%',
  4366.                 PEAR_CHANNELFILE_ERROR_NO_NAME =>
  4367.                     'Missing channel name',
  4368.                 PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
  4369.                     'Invalid channel %tag% "%name%"',
  4370.                 PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
  4371.                     'Missing channel summary',
  4372.                 PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
  4373.                     'Channel summary should be on one line, but is multi-line',
  4374.                 PEAR_CHANNELFILE_ERROR_NO_HOST =>
  4375.                     'Missing channel server for %type% server',
  4376.                 PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
  4377.                     'Server name "%server%" is invalid for %type% server',
  4378.                 PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
  4379.                     'Invalid mirror name "%name%", mirror type %type%',
  4380.                 PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
  4381.                     'Invalid mirror type "%type%"',
  4382.                 PEAR_CHANNELFILE_ERROR_INVALID =>
  4383.                     'Cannot generate xml, contents are invalid',
  4384.                 PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
  4385.                     'packagenameregex cannot be empty',
  4386.                 PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
  4387.                     '%parent% %protocol% function has no version',
  4388.                 PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
  4389.                     '%parent% %protocol% function has no name',
  4390.                 PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
  4391.                     '%parent% rest baseurl has no type',
  4392.                 PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
  4393.                     'Validation package has no name in <validatepackage> tag',
  4394.                 PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
  4395.                     'Validation package "%package%" has no version',
  4396.                 PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
  4397.                     'Mirror "%mirror%" does not exist',
  4398.                 PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
  4399.                     'Port "%port%" must be numeric',
  4400.                 PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
  4401.                     '<static> tag must contain version attribute',
  4402.                 PEAR_CHANNELFILE_URI_CANT_MIRROR =>
  4403.                     'The __uri pseudo-channel cannot have mirrors',
  4404.                 PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
  4405.                     '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
  4406.             );
  4407.     }
  4408.  
  4409.     /**
  4410.      * @param string contents of package.xml file
  4411.      * @return bool success of parsing
  4412.      */
  4413.     function fromXmlString($data)
  4414.     {
  4415.         if (preg_match('/<channel\s+version="([0-9]+\.[0-9]+)"/', $data, $channelversion)) {
  4416.             if (!in_array($channelversion[1], $this->_supportedVersions)) {
  4417.                 $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
  4418.                     array('version' => $channelversion[1]));
  4419.                 return false;
  4420.             }
  4421.             $parser = new PEAR_XMLParser;
  4422.             $result = $parser->parse($data);
  4423.             if ($result !== true) {
  4424.                 if ($result->getCode() == 1) {
  4425.                     $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
  4426.                         array('error' => $error));
  4427.                 } else {
  4428.                     $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
  4429.                 }
  4430.                 return false;
  4431.             }
  4432.             $this->_channelInfo = $parser->getData();
  4433.             return true;
  4434.         } else {
  4435.             $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
  4436.             return false;
  4437.         }
  4438.     }
  4439.     
  4440.     /**
  4441.      * @return array
  4442.      */
  4443.     function toArray()
  4444.     {
  4445.         if (!$this->_isValid && !$this->validate()) {
  4446.             return false;
  4447.         }
  4448.         return $this->_channelInfo;
  4449.     }
  4450.     
  4451.     /**
  4452.      * @param array
  4453.      * @static
  4454.      * @return PEAR_ChannelFile|false false if invalid
  4455.      */
  4456.     function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack')
  4457.     {
  4458.         $a = new PEAR_ChannelFile($compatibility, $stackClass);
  4459.         $a->_fromArray($data);
  4460.         if (!$a->validate()) {
  4461.             $a = false;
  4462.             return $a;
  4463.         }
  4464.         return $a;
  4465.     }
  4466.  
  4467.     /**
  4468.      * Unlike {@link fromArray()} this does not do any validation
  4469.      * @param array
  4470.      * @static
  4471.      * @return PEAR_ChannelFile
  4472.      */
  4473.     function &fromArrayWithErrors($data, $compatibility = false,
  4474.                                   $stackClass = 'PEAR_ErrorStack')
  4475.     {
  4476.         $a = new PEAR_ChannelFile($compatibility, $stackClass);
  4477.         $a->_fromArray($data);
  4478.         return $a;
  4479.     }
  4480.     
  4481.     /**
  4482.      * @param array
  4483.      * @access private
  4484.      */
  4485.     function _fromArray($data)
  4486.     {
  4487.         $this->_channelInfo = $data;
  4488.     }
  4489.     
  4490.     /**
  4491.      * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  4492.      * @param boolean determines whether to purge the error stack after retrieving
  4493.      * @return array
  4494.      */
  4495.     function getErrors($purge = false)
  4496.     {
  4497.         return $this->_stack->getErrors($purge);
  4498.     }
  4499.  
  4500.     /**
  4501.      * Unindent given string (?)
  4502.      *
  4503.      * @param string $str The string that has to be unindented.
  4504.      * @return string
  4505.      * @access private
  4506.      */
  4507.     function _unIndent($str)
  4508.     {
  4509.         // remove leading newlines
  4510.         $str = preg_replace('/^[\r\n]+/', '', $str);
  4511.         // find whitespace at the beginning of the first line
  4512.         $indent_len = strspn($str, " \t");
  4513.         $indent = substr($str, 0, $indent_len);
  4514.         $data = '';
  4515.         // remove the same amount of whitespace from following lines
  4516.         foreach (explode("\n", $str) as $line) {
  4517.             if (substr($line, 0, $indent_len) == $indent) {
  4518.                 $data .= substr($line, $indent_len) . "\n";
  4519.             }
  4520.         }
  4521.         return $data;
  4522.     }
  4523.  
  4524.     /**
  4525.      * Parse a channel.xml file.  Expects the name of
  4526.      * a channel xml file as input.
  4527.      *
  4528.      * @param string  $descfile  name of channel xml file
  4529.      * @return bool success of parsing
  4530.      */
  4531.     function fromXmlFile($descfile)
  4532.     {
  4533.         if (!file_exists($descfile) || !is_file($descfile) || !is_readable($descfile) ||
  4534.              (!$fp = fopen($descfile, 'r'))) {
  4535.             require_once 'phar://go-pear.phar/PEAR.php';
  4536.             return PEAR::raiseError("Unable to open $descfile");
  4537.         }
  4538.  
  4539.         // read the whole thing so we only get one cdata callback
  4540.         // for each block of cdata
  4541.         fclose($fp);
  4542.         $data = file_get_contents($descfile);
  4543.         return $this->fromXmlString($data);
  4544.     }
  4545.  
  4546.     /**
  4547.      * Parse channel information from different sources
  4548.      *
  4549.      * This method is able to extract information about a channel
  4550.      * from an .xml file or a string
  4551.      *
  4552.      * @access public
  4553.      * @param  string Filename of the source or the source itself
  4554.      * @return bool
  4555.      */
  4556.     function fromAny($info)
  4557.     {
  4558.         if (is_string($info) && file_exists($info) && strlen($info) < 255) {
  4559.             $tmp = substr($info, -4);
  4560.             if ($tmp == '.xml') {
  4561.                 $info = $this->fromXmlFile($info);
  4562.             } else {
  4563.                 $fp = fopen($info, "r");
  4564.                 $test = fread($fp, 5);
  4565.                 fclose($fp);
  4566.                 if ($test == "<?xml") {
  4567.                     $info = $this->fromXmlFile($info);
  4568.                 }
  4569.             }
  4570.             if (PEAR::isError($info)) {
  4571.                 require_once 'phar://go-pear.phar/PEAR.php';
  4572.                 return PEAR::raiseError($info);
  4573.             }
  4574.         }
  4575.         if (is_string($info)) {
  4576.             $info = $this->fromXmlString($info);
  4577.         }
  4578.         return $info;
  4579.     }
  4580.  
  4581.     /**
  4582.      * Return an XML document based on previous parsing and modifications
  4583.      *
  4584.      * @return string XML data
  4585.      *
  4586.      * @access public
  4587.      */
  4588.     function toXml()
  4589.     {
  4590.         if (!$this->_isValid && !$this->validate()) {
  4591.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
  4592.             return false;
  4593.         }
  4594.         if (!isset($this->_channelInfo['attribs']['version'])) {
  4595.             $this->_channelInfo['attribs']['version'] = '1.0';
  4596.         }
  4597.         $channelInfo = $this->_channelInfo;
  4598.         $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
  4599.         $ret .= "<channel version=\"" .
  4600.             $channelInfo['attribs']['version'] . "\" xmlns=\"http://pear.php.net/channel-1.0\"
  4601.   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  4602.   xsi:schemaLocation=\"http://pear.php.net/dtd/channel-"
  4603.             . $channelInfo['attribs']['version'] . " http://pear.php.net/dtd/channel-" .
  4604.             $channelInfo['attribs']['version'] . ".xsd\">
  4605.  <name>$channelInfo[name]</name>
  4606.  <summary>" . htmlspecialchars($channelInfo['summary'])."</summary>
  4607. ";
  4608.         if (isset($channelInfo['suggestedalias'])) {
  4609.             $ret .= ' <suggestedalias>' . $channelInfo['suggestedalias'] . "</suggestedalias>\n";
  4610.         }
  4611.         if (isset($channelInfo['validatepackage'])) {
  4612.             $ret .= ' <validatepackage version="' .
  4613.                 $channelInfo['validatepackage']['attribs']['version']. '">' .
  4614.                 htmlspecialchars($channelInfo['validatepackage']['_content']) .
  4615.                 "</validatepackage>\n";
  4616.         }
  4617.         $ret .= " <servers>\n";
  4618.         $ret .= '  <primary';
  4619.         if (isset($channelInfo['servers']['primary']['attribs']['ssl'])) {
  4620.             $ret .= ' ssl="' . $channelInfo['servers']['primary']['attribs']['ssl'] . '"';
  4621.         }
  4622.         if (isset($channelInfo['servers']['primary']['attribs']['port'])) {
  4623.             $ret .= ' port="' . $channelInfo['servers']['primary']['attribs']['port'] . '"';
  4624.         }
  4625.         $ret .= ">\n";
  4626.         if (isset($channelInfo['servers']['primary']['xmlrpc'])) {
  4627.             $ret .= $this->_makeXmlrpcXml($channelInfo['servers']['primary']['xmlrpc'], '   ');
  4628.         }
  4629.         if (isset($channelInfo['servers']['primary']['rest'])) {
  4630.             $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], '   ');
  4631.         }
  4632.         if (isset($channelInfo['servers']['primary']['soap'])) {
  4633.             $ret .= $this->_makeSoapXml($channelInfo['servers']['primary']['soap'], '   ');
  4634.         }
  4635.         $ret .= "  </primary>\n";
  4636.         if (isset($channelInfo['servers']['mirror'])) {
  4637.             $ret .= $this->_makeMirrorsXml($channelInfo);
  4638.         }
  4639.         $ret .= " </servers>\n";
  4640.         $ret .= "</channel>";
  4641.         return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
  4642.     }
  4643.  
  4644.     /**
  4645.      * Generate the <xmlrpc> tag
  4646.      * @access private
  4647.      */
  4648.     function _makeXmlrpcXml($info, $indent)
  4649.     {
  4650.         $ret = $indent . "<xmlrpc";
  4651.         if (isset($info['attribs']['path'])) {
  4652.             $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"';
  4653.         }
  4654.         $ret .= ">\n";
  4655.         $ret .= $this->_makeFunctionsXml($info['function'], "$indent ");
  4656.         $ret .= $indent . "</xmlrpc>\n";
  4657.         return $ret;
  4658.     }
  4659.  
  4660.     /**
  4661.      * Generate the <soap> tag
  4662.      * @access private
  4663.      */
  4664.     function _makeSoapXml($info, $indent)
  4665.     {
  4666.         $ret = $indent . "<soap";
  4667.         if (isset($info['attribs']['path'])) {
  4668.             $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"';
  4669.         }
  4670.         $ret .= ">\n";
  4671.         $ret .= $this->_makeFunctionsXml($info['function'], "$indent ");
  4672.         $ret .= $indent . "</soap>\n";
  4673.         return $ret;
  4674.     }
  4675.  
  4676.     /**
  4677.      * Generate the <rest> tag
  4678.      * @access private
  4679.      */
  4680.     function _makeRestXml($info, $indent)
  4681.     {
  4682.         $ret = $indent . "<rest>\n";
  4683.         if (!isset($info['baseurl'][0])) {
  4684.             $info['baseurl'] = array($info['baseurl']);
  4685.         }
  4686.         foreach ($info['baseurl'] as $url) {
  4687.             $ret .= "$indent <baseurl type=\"" . $url['attribs']['type'] . "\"";
  4688.             $ret .= ">" . $url['_content'] . "</baseurl>\n";
  4689.         }
  4690.         $ret .= $indent . "</rest>\n";
  4691.         return $ret;
  4692.     }
  4693.  
  4694.     /**
  4695.      * Generate the <mirrors> tag
  4696.      * @access private
  4697.      */
  4698.     function _makeMirrorsXml($channelInfo)
  4699.     {
  4700.         $ret = "";
  4701.         if (!isset($channelInfo['servers']['mirror'][0])) {
  4702.             $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
  4703.         }
  4704.         foreach ($channelInfo['servers']['mirror'] as $mirror) {
  4705.             $ret .= '  <mirror host="' . $mirror['attribs']['host'] . '"';
  4706.             if (isset($mirror['attribs']['port'])) {
  4707.                 $ret .= ' port="' . $mirror['attribs']['port'] . '"';
  4708.             }
  4709.             if (isset($mirror['attribs']['ssl'])) {
  4710.                 $ret .= ' ssl="' . $mirror['attribs']['ssl'] . '"';
  4711.             }
  4712.             $ret .= ">\n";
  4713.             if (isset($mirror['xmlrpc']) || isset($mirror['soap'])) {
  4714.                 if (isset($mirror['xmlrpc'])) {
  4715.                     $ret .= $this->_makeXmlrpcXml($mirror['xmlrpc'], '   ');
  4716.                 }
  4717.                 if (isset($mirror['rest'])) {
  4718.                     $ret .= $this->_makeRestXml($mirror['rest'], '   ');
  4719.                 }
  4720.                 if (isset($mirror['soap'])) {
  4721.                     $ret .= $this->_makeSoapXml($mirror['soap'], '   ');
  4722.                 }
  4723.                 $ret .= "  </mirror>\n";
  4724.             } else {
  4725.                 $ret .= "/>\n";
  4726.             }
  4727.         }
  4728.         return $ret;
  4729.     }
  4730.  
  4731.     /**
  4732.      * Generate the <functions> tag
  4733.      * @access private
  4734.      */
  4735.     function _makeFunctionsXml($functions, $indent, $rest = false)
  4736.     {
  4737.         $ret = '';
  4738.         if (!isset($functions[0])) {
  4739.             $functions = array($functions);
  4740.         }
  4741.         foreach ($functions as $function) {
  4742.             $ret .= "$indent<function version=\"" . $function['attribs']['version'] . "\"";
  4743.             if ($rest) {
  4744.                 $ret .= ' uri="' . $function['attribs']['uri'] . '"';
  4745.             }
  4746.             $ret .= ">" . $function['_content'] . "</function>\n";
  4747.         }
  4748.         return $ret;
  4749.     }
  4750.  
  4751.     /**
  4752.      * Validation error.  Also marks the object contents as invalid
  4753.      * @param error code
  4754.      * @param array error information
  4755.      * @access private
  4756.      */
  4757.     function _validateError($code, $params = array())
  4758.     {
  4759.         $this->_stack->push($code, 'error', $params);
  4760.         $this->_isValid = false;
  4761.     }
  4762.  
  4763.     /**
  4764.      * Validation warning.  Does not mark the object contents invalid.
  4765.      * @param error code
  4766.      * @param array error information
  4767.      * @access private
  4768.      */
  4769.     function _validateWarning($code, $params = array())
  4770.     {
  4771.         $this->_stack->push($code, 'warning', $params);
  4772.     }
  4773.  
  4774.     /**
  4775.      * Validate parsed file.
  4776.      *
  4777.      * @access public
  4778.      * @return boolean
  4779.      */
  4780.     function validate()
  4781.     {
  4782.         $this->_isValid = true;
  4783.         $info = $this->_channelInfo;
  4784.         if (empty($info['name'])) {
  4785.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
  4786.         } elseif (!$this->validChannelServer($info['name'])) {
  4787.             if ($info['name'] != '__uri') {
  4788.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
  4789.                     'name' => $info['name']));
  4790.             }
  4791.         }
  4792.         if (empty($info['summary'])) {
  4793.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  4794.         } elseif (strpos(trim($info['summary']), "\n") !== false) {
  4795.             $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  4796.                 array('summary' => $info['summary']));
  4797.         }
  4798.         if (isset($info['suggestedalias'])) {
  4799.             if (!$this->validChannelServer($info['suggestedalias'])) {
  4800.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  4801.                     array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
  4802.             }
  4803.         }
  4804.         if (isset($info['localalias'])) {
  4805.             if (!$this->validChannelServer($info['localalias'])) {
  4806.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  4807.                     array('tag' => 'localalias', 'name' =>$info['localalias']));
  4808.             }
  4809.         }
  4810.         if (isset($info['validatepackage'])) {
  4811.             if (!isset($info['validatepackage']['_content'])) {
  4812.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
  4813.             }
  4814.             if (!isset($info['validatepackage']['attribs']['version'])) {
  4815.                 $content = isset($info['validatepackage']['_content']) ?
  4816.                     $info['validatepackage']['_content'] :
  4817.                     null;
  4818.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
  4819.                     array('package' => $content));
  4820.             }
  4821.         }
  4822.         if (isset($info['servers']['primary']['attribs']['port']) &&
  4823.               !is_numeric($info['servers']['primary']['attribs']['port'])) {
  4824.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
  4825.                 array('port' => $info['servers']['primary']['attribs']['port']));
  4826.         }
  4827.         if (isset($info['servers']['primary']['attribs']['ssl']) &&
  4828.               $info['servers']['primary']['attribs']['ssl'] != 'yes') {
  4829.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  4830.                 array('ssl' => $info['servers']['primary']['attribs']['ssl'],
  4831.                     'server' => $info['name']));
  4832.         }
  4833.  
  4834.         if (isset($info['servers']['primary']['xmlrpc']) &&
  4835.               isset($info['servers']['primary']['xmlrpc']['function'])) {
  4836.             $this->_validateFunctions('xmlrpc', $info['servers']['primary']['xmlrpc']['function']);
  4837.         }
  4838.         if (isset($info['servers']['primary']['soap']) &&
  4839.               isset($info['servers']['primary']['soap']['function'])) {
  4840.             $this->_validateFunctions('soap', $info['servers']['primary']['soap']['function']);
  4841.         }
  4842.         if (isset($info['servers']['primary']['rest']) &&
  4843.               isset($info['servers']['primary']['rest']['baseurl'])) {
  4844.             $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
  4845.         }
  4846.         if (isset($info['servers']['mirror'])) {
  4847.             if ($this->_channelInfo['name'] == '__uri') {
  4848.                 $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
  4849.             }
  4850.             if (!isset($info['servers']['mirror'][0])) {
  4851.                 $info['servers']['mirror'] = array($info['servers']['mirror']);
  4852.             }
  4853.             $i = 0;
  4854.             foreach ($info['servers']['mirror'] as $mirror) {
  4855.                 if (!isset($mirror['attribs']['host'])) {
  4856.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
  4857.                       array('type' => 'mirror'));
  4858.                 } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
  4859.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
  4860.                         array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
  4861.                 }
  4862.                 if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
  4863.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  4864.                         array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
  4865.                 }
  4866.                 if (isset($mirror['xmlrpc'])) {
  4867.                     $this->_validateFunctions('xmlrpc',
  4868.                         $mirror['xmlrpc']['function'], $mirror['attribs']['host']);
  4869.                 }
  4870.                 if (isset($mirror['soap'])) {
  4871.                     $this->_validateFunctions('soap', $mirror['soap']['function'],
  4872.                         $mirror['attribs']['host']);
  4873.                 }
  4874.                 if (isset($mirror['rest'])) {
  4875.                     $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
  4876.                         $mirror['attribs']['host']);
  4877.                 }
  4878.             }
  4879.         }
  4880.         return $this->_isValid;
  4881.     }
  4882.  
  4883.     /**
  4884.      * @param string xmlrpc or soap - protocol name this function applies to
  4885.      * @param array the functions
  4886.      * @param string the name of the parent element (mirror name, for instance)
  4887.      */
  4888.     function _validateFunctions($protocol, $functions, $parent = '')
  4889.     {
  4890.         if (!isset($functions[0])) {
  4891.             $functions = array($functions);
  4892.         }
  4893.         foreach ($functions as $function) {
  4894.             if (!isset($function['_content']) || empty($function['_content'])) {
  4895.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
  4896.                     array('parent' => $parent, 'protocol' => $protocol));
  4897.             }
  4898.             if ($protocol == 'rest') {
  4899.                 if (!isset($function['attribs']['type']) ||
  4900.                       empty($function['attribs']['type'])) {
  4901.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE,
  4902.                         array('parent' => $parent, 'protocol' => $protocol));
  4903.                 }
  4904.             } else {
  4905.                 if (!isset($function['attribs']['version']) ||
  4906.                       empty($function['attribs']['version'])) {
  4907.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
  4908.                         array('parent' => $parent, 'protocol' => $protocol));
  4909.                 }
  4910.             }
  4911.         }
  4912.     }
  4913.  
  4914.     /**
  4915.      * Test whether a string contains a valid channel server.
  4916.      * @param string $ver the package version to test
  4917.      * @return bool
  4918.      */
  4919.     function validChannelServer($server)
  4920.     {
  4921.         if ($server == '__uri') {
  4922.             return true;
  4923.         }
  4924.         return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
  4925.     }
  4926.  
  4927.     /**
  4928.      * @return string|false
  4929.      */
  4930.     function getName()
  4931.     {
  4932.         if (isset($this->_channelInfo['name'])) {
  4933.             return $this->_channelInfo['name'];
  4934.         } else {
  4935.             return false;
  4936.         }
  4937.     }
  4938.  
  4939.     /**
  4940.      * @return string|false
  4941.      */
  4942.     function getServer()
  4943.     {
  4944.         if (isset($this->_channelInfo['name'])) {
  4945.             return $this->_channelInfo['name'];
  4946.         } else {
  4947.             return false;
  4948.         }
  4949.     }
  4950.  
  4951.     /**
  4952.      * @return int|80 port number to connect to
  4953.      */
  4954.     function getPort($mirror = false)
  4955.     {
  4956.         if ($mirror) {
  4957.             if ($mir = $this->getMirror($mirror)) {
  4958.                 if (isset($mir['attribs']['port'])) {
  4959.                     return $mir['attribs']['port'];
  4960.                 } else {
  4961.                     if ($this->getSSL($mirror)) {
  4962.                         return 443;
  4963.                     }
  4964.                     return 80;
  4965.                 }
  4966.             }
  4967.             return false;
  4968.         }
  4969.         if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
  4970.             return $this->_channelInfo['servers']['primary']['attribs']['port'];
  4971.         }
  4972.         if ($this->getSSL()) {
  4973.             return 443;
  4974.         }
  4975.         return 80;
  4976.     }
  4977.  
  4978.     /**
  4979.      * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
  4980.      */
  4981.     function getSSL($mirror = false)
  4982.     {
  4983.         if ($mirror) {
  4984.             if ($mir = $this->getMirror($mirror)) {
  4985.                 if (isset($mir['attribs']['ssl'])) {
  4986.                     return true;
  4987.                 } else {
  4988.                     return false;
  4989.                 }
  4990.             }
  4991.             return false;
  4992.         }
  4993.         if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  4994.             return true;
  4995.         }
  4996.         return false;
  4997.     }
  4998.  
  4999.     /**
  5000.      * @return string|false
  5001.      */
  5002.     function getSummary()
  5003.     {
  5004.         if (isset($this->_channelInfo['summary'])) {
  5005.             return $this->_channelInfo['summary'];
  5006.         } else {
  5007.             return false;
  5008.         }
  5009.     }
  5010.  
  5011.     /**
  5012.      * @param string xmlrpc or soap
  5013.      * @param string|false mirror name or false for primary server
  5014.      */
  5015.     function getPath($protocol, $mirror = false)
  5016.     {   
  5017.         if (!in_array($protocol, array('xmlrpc', 'soap'))) {
  5018.             return false;
  5019.         }
  5020.         if ($mirror) {
  5021.             if (!($mir = $this->getMirror($mirror))) {
  5022.                 return false;
  5023.             }
  5024.             if (isset($mir[$protocol]['attribs']['path'])) {
  5025.                 return $mir[$protocol]['attribs']['path'];
  5026.             } else {
  5027.                 return $protocol . '.php';
  5028.             }
  5029.         } elseif (isset($this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'])) {
  5030.             return $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'];
  5031.         }
  5032.         return $protocol . '.php';
  5033.     }
  5034.  
  5035.     /**
  5036.      * @param string protocol type (xmlrpc, soap)
  5037.      * @param string Mirror name
  5038.      * @return array|false
  5039.      */
  5040.     function getFunctions($protocol, $mirror = false)
  5041.     {
  5042.         if ($this->getName() == '__uri') {
  5043.             return false;
  5044.         }
  5045.         if ($protocol == 'rest') {
  5046.             $function = 'baseurl';
  5047.         } else {
  5048.             $function = 'function';
  5049.         }
  5050.         if ($mirror) {
  5051.             if ($mir = $this->getMirror($mirror)) {
  5052.                 if (isset($mir[$protocol][$function])) {
  5053.                     return $mir[$protocol][$function];
  5054.                 }
  5055.             }
  5056.             return false;
  5057.         }
  5058.         if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
  5059.             return $this->_channelInfo['servers']['primary'][$protocol][$function];
  5060.         } else {
  5061.             return false;
  5062.         }
  5063.     }
  5064.  
  5065.     /**
  5066.      * @param string Protocol type
  5067.      * @param string Function name (null to return the
  5068.      *               first protocol of the type requested)
  5069.      * @param string Mirror name, if any
  5070.      * @return array
  5071.      */
  5072.      function getFunction($type, $name = null, $mirror = false)
  5073.      {
  5074.         $protocols = $this->getFunctions($type, $mirror);
  5075.         if (!$protocols) {
  5076.             return false;
  5077.         }
  5078.         foreach ($protocols as $protocol) {
  5079.             if ($name === null) {
  5080.                 return $protocol;
  5081.             }
  5082.             if ($protocol['_content'] != $name) {
  5083.                 continue;
  5084.             }
  5085.             return $protocol;
  5086.         }
  5087.         return false;
  5088.      }
  5089.  
  5090.     /**
  5091.      * @param string protocol type
  5092.      * @param string protocol name
  5093.      * @param string version
  5094.      * @param string mirror name
  5095.      * @return boolean
  5096.      */
  5097.     function supports($type, $name = null, $mirror = false, $version = '1.0')
  5098.     {
  5099.         $protocols = $this->getFunctions($type, $mirror);
  5100.         if (!$protocols) {
  5101.             return false;
  5102.         }
  5103.         foreach ($protocols as $protocol) {
  5104.             if ($protocol['attribs']['version'] != $version) {
  5105.                 continue;
  5106.             }
  5107.             if ($name === null) {
  5108.                 return true;
  5109.             }
  5110.             if ($protocol['_content'] != $name) {
  5111.                 continue;
  5112.             }
  5113.             return true;
  5114.         }
  5115.         return false;
  5116.     }
  5117.  
  5118.     /**
  5119.      * Determines whether a channel supports Representational State Transfer (REST) protocols
  5120.      * for retrieving channel information
  5121.      * @param string
  5122.      * @return bool
  5123.      */
  5124.     function supportsREST($mirror = false)
  5125.     {
  5126.         if ($mirror == $this->_channelInfo['name']) {
  5127.             $mirror = false;
  5128.         }
  5129.         if ($mirror) {
  5130.             if ($mir = $this->getMirror($mirror)) {
  5131.                 return isset($mir['rest']);
  5132.             }
  5133.             return false;
  5134.         }
  5135.         return isset($this->_channelInfo['servers']['primary']['rest']);
  5136.     }
  5137.  
  5138.     /**
  5139.      * Get the URL to access a base resource.
  5140.      *
  5141.      * Hyperlinks in the returned xml will be used to retrieve the proper information
  5142.      * needed.  This allows extreme extensibility and flexibility in implementation
  5143.      * @param string Resource Type to retrieve
  5144.      */
  5145.     function getBaseURL($resourceType, $mirror = false)
  5146.     {
  5147.         if ($mirror == $this->_channelInfo['name']) {
  5148.             $mirror = false;
  5149.         }
  5150.         if ($mirror) {
  5151.             if ($mir = $this->getMirror($mirror)) {
  5152.                 $rest = $mir['rest'];
  5153.             } else {
  5154.                 return false;
  5155.             }
  5156.             $server = $mirror;
  5157.         } else {
  5158.             $rest = $this->_channelInfo['servers']['primary']['rest'];
  5159.             $server = $this->getServer();
  5160.         }
  5161.         if (!isset($rest['baseurl'][0])) {
  5162.             $rest['baseurl'] = array($rest['baseurl']);
  5163.         }
  5164.         foreach ($rest['baseurl'] as $baseurl) {
  5165.             if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
  5166.                 return $baseurl['_content'];
  5167.             }
  5168.         }
  5169.         return false;
  5170.     }
  5171.  
  5172.     /**
  5173.      * Since REST does not implement RPC, provide this as a logical wrapper around
  5174.      * resetFunctions for REST
  5175.      * @param string|false mirror name, if any
  5176.      */
  5177.     function resetREST($mirror = false)
  5178.     {
  5179.         return $this->resetFunctions('rest', $mirror);
  5180.     }
  5181.  
  5182.     /**
  5183.      * Empty all protocol definitions
  5184.      * @param string protocol type (xmlrpc, soap)
  5185.      * @param string|false mirror name, if any
  5186.      */
  5187.     function resetFunctions($type, $mirror = false)
  5188.     {
  5189.         if ($mirror) {
  5190.             if (isset($this->_channelInfo['servers']['mirror'])) {
  5191.                 $mirrors = $this->_channelInfo['servers']['mirror'];
  5192.                 if (!isset($mirrors[0])) {
  5193.                     $mirrors = array($mirrors);
  5194.                 }
  5195.                 foreach ($mirrors as $i => $mir) {
  5196.                     if ($mir['attribs']['host'] == $mirror) {
  5197.                         if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
  5198.                             unset($this->_channelInfo['servers']['mirror'][$i][$type]);
  5199.                         }
  5200.                         return true;
  5201.                     }
  5202.                 }
  5203.                 return false;
  5204.             } else {
  5205.                 return false;
  5206.             }
  5207.         } else {
  5208.             if (isset($this->_channelInfo['servers']['primary'][$type])) {
  5209.                 unset($this->_channelInfo['servers']['primary'][$type]);
  5210.             }
  5211.             return true;
  5212.         }
  5213.     }
  5214.  
  5215.     /**
  5216.      * Set a channel's protocols to the protocols supported by pearweb
  5217.      */
  5218.     function setDefaultPEARProtocols($version = '1.0', $mirror = false)
  5219.     {
  5220.         switch ($version) {
  5221.             case '1.0' :
  5222.                 $this->resetFunctions('xmlrpc', $mirror);
  5223.                 $this->resetFunctions('soap', $mirror);
  5224.                 $this->resetREST($mirror);
  5225.                 $this->addFunction('xmlrpc', '1.0', 'logintest', $mirror);
  5226.                 $this->addFunction('xmlrpc', '1.0', 'package.listLatestReleases', $mirror);
  5227.                 $this->addFunction('xmlrpc', '1.0', 'package.listAll', $mirror);
  5228.                 $this->addFunction('xmlrpc', '1.0', 'package.info', $mirror);
  5229.                 $this->addFunction('xmlrpc', '1.0', 'package.getDownloadURL', $mirror);
  5230.                 $this->addFunction('xmlrpc', '1.1', 'package.getDownloadURL', $mirror);
  5231.                 $this->addFunction('xmlrpc', '1.0', 'package.getDepDownloadURL', $mirror);
  5232.                 $this->addFunction('xmlrpc', '1.1', 'package.getDepDownloadURL', $mirror);
  5233.                 $this->addFunction('xmlrpc', '1.0', 'package.search', $mirror);
  5234.                 $this->addFunction('xmlrpc', '1.0', 'channel.listAll', $mirror);
  5235.                 return true;
  5236.             break;
  5237.             default :
  5238.                 return false;
  5239.             break;
  5240.         }
  5241.     }
  5242.     
  5243.     /**
  5244.      * @return array
  5245.      */
  5246.     function getMirrors()
  5247.     {
  5248.         if (isset($this->_channelInfo['servers']['mirror'])) {
  5249.             $mirrors = $this->_channelInfo['servers']['mirror'];
  5250.             if (!isset($mirrors[0])) {
  5251.                 $mirrors = array($mirrors);
  5252.             }
  5253.             return $mirrors;
  5254.         } else {
  5255.             return array();
  5256.         }
  5257.     }
  5258.  
  5259.     /**
  5260.      * Get the unserialized XML representing a mirror
  5261.      * @return array|false
  5262.      */
  5263.     function getMirror($server)
  5264.     {
  5265.         foreach ($this->getMirrors() as $mirror) {
  5266.             if ($mirror['attribs']['host'] == $server) {
  5267.                 return $mirror;
  5268.             }
  5269.         }
  5270.         return false;
  5271.     }
  5272.  
  5273.     /**
  5274.      * @param string
  5275.      * @return string|false
  5276.      * @error PEAR_CHANNELFILE_ERROR_NO_NAME
  5277.      * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
  5278.      */
  5279.     function setName($name)
  5280.     {
  5281.         return $this->setServer($name);
  5282.     }
  5283.  
  5284.     /**
  5285.      * Set the socket number (port) that is used to connect to this channel
  5286.      * @param integer
  5287.      * @param string|false name of the mirror server, or false for the primary
  5288.      */
  5289.     function setPort($port, $mirror = false)
  5290.     {
  5291.         if ($mirror) {
  5292.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  5293.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5294.                     array('mirror' => $mirror));
  5295.                 return false;
  5296.             }
  5297.             $setmirror = false;
  5298.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  5299.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  5300.                     if ($mirror == $mir['attribs']['host']) {
  5301.                         $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
  5302.                         return true;
  5303.                     }
  5304.                 }
  5305.                 return false;
  5306.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  5307.                 $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
  5308.                 $this->_isValid = false;
  5309.                 return true;
  5310.             }
  5311.         }
  5312.         $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
  5313.         $this->_isValid = false;
  5314.         return true;
  5315.     }
  5316.  
  5317.     /**
  5318.      * Set the socket number (port) that is used to connect to this channel
  5319.      * @param bool Determines whether to turn on SSL support or turn it off
  5320.      * @param string|false name of the mirror server, or false for the primary
  5321.      */
  5322.     function setSSL($ssl = true, $mirror = false)
  5323.     {
  5324.         if ($mirror) {
  5325.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  5326.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5327.                     array('mirror' => $mirror));
  5328.                 return false;
  5329.             }
  5330.             $setmirror = false;
  5331.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  5332.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  5333.                     if ($mirror == $mir['attribs']['host']) {
  5334.                         if (!$ssl) {
  5335.                             if (isset($this->_channelInfo['servers']['mirror'][$i]
  5336.                                   ['attribs']['ssl'])) {
  5337.                                 unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
  5338.                             }
  5339.                         } else {
  5340.                             $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
  5341.                         }
  5342.                         return true;
  5343.                     }
  5344.                 }
  5345.                 return false;
  5346.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  5347.                 if (!$ssl) {
  5348.                     if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
  5349.                         unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
  5350.                     }
  5351.                 } else {
  5352.                     $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
  5353.                 }
  5354.                 $this->_isValid = false;
  5355.                 return true;
  5356.             }
  5357.         }
  5358.         if ($ssl) {
  5359.             $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
  5360.         } else {
  5361.             if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  5362.                 unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
  5363.             }
  5364.         }
  5365.         $this->_isValid = false;
  5366.         return true;
  5367.     }
  5368.  
  5369.     /**
  5370.      * Set the socket number (port) that is used to connect to this channel
  5371.      * @param integer
  5372.      * @param string|false name of the mirror server, or false for the primary
  5373.      */
  5374.     function setPath($protocol, $path, $mirror = false)
  5375.     {
  5376.         if (!in_array($protocol, array('xmlrpc', 'soap'))) {
  5377.             return false;
  5378.         }
  5379.         if ($mirror) {
  5380.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  5381.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5382.                     array('mirror' => $mirror));
  5383.                 return false;
  5384.             }
  5385.             $setmirror = false;
  5386.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  5387.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  5388.                     if ($mirror == $mir['attribs']['host']) {
  5389.                         $this->_channelInfo['servers']['mirror'][$i][$protocol]['attribs']['path'] =
  5390.                             $path;
  5391.                         return true;
  5392.                     }
  5393.                 }
  5394.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5395.                     array('mirror' => $mirror));
  5396.                 return false;
  5397.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  5398.                 $this->_channelInfo['servers']['mirror'][$protocol]['attribs']['path'] = $path;
  5399.                 $this->_isValid = false;
  5400.                 return true;
  5401.             }
  5402.         }
  5403.         $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'] = $path;
  5404.         $this->_isValid = false;
  5405.         return true;
  5406.     }
  5407.  
  5408.     /**
  5409.      * @param string
  5410.      * @return string|false
  5411.      * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
  5412.      * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
  5413.      */
  5414.     function setServer($server, $mirror = false)
  5415.     {
  5416.         if (empty($server)) {
  5417.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
  5418.             return false;
  5419.         } elseif (!$this->validChannelServer($server)) {
  5420.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  5421.                 array('tag' => 'name', 'name' => $server));
  5422.             return false;
  5423.         }
  5424.         if ($mirror) {
  5425.             $found = false;
  5426.             foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  5427.                 if ($mirror == $mir['attribs']['host']) {
  5428.                     $found = true;
  5429.                     break;
  5430.                 }
  5431.             }
  5432.             if (!$found) {
  5433.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5434.                     array('mirror' => $mirror));
  5435.                 return false;
  5436.             }
  5437.             $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
  5438.             return true;
  5439.         }
  5440.         $this->_channelInfo['name'] = $server;
  5441.         return true;
  5442.     }
  5443.  
  5444.     /**
  5445.      * @param string
  5446.      * @return boolean success
  5447.      * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
  5448.      * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
  5449.      */
  5450.     function setSummary($summary)
  5451.     {
  5452.         if (empty($summary)) {
  5453.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  5454.             return false;
  5455.         } elseif (strpos(trim($summary), "\n") !== false) {
  5456.             $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  5457.                 array('summary' => $summary));
  5458.         }
  5459.         $this->_channelInfo['summary'] = $summary;
  5460.         return true;
  5461.     }
  5462.  
  5463.     /**
  5464.      * @param string
  5465.      * @param boolean determines whether the alias is in channel.xml or local
  5466.      * @return boolean success
  5467.      */
  5468.     function setAlias($alias, $local = false)
  5469.     {
  5470.         if (!$this->validChannelServer($alias)) {
  5471.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  5472.                 array('tag' => 'suggestedalias', 'name' => $alias));
  5473.             return false;
  5474.         }
  5475.         if ($local) {
  5476.             $this->_channelInfo['localalias'] = $alias;
  5477.         } else {
  5478.             $this->_channelInfo['suggestedalias'] = $alias;
  5479.         }
  5480.         return true;
  5481.     }
  5482.  
  5483.     /**
  5484.      * @return string
  5485.      */
  5486.     function getAlias()
  5487.     {
  5488.         if (isset($this->_channelInfo['localalias'])) {
  5489.             return $this->_channelInfo['localalias'];
  5490.         }
  5491.         if (isset($this->_channelInfo['suggestedalias'])) {
  5492.             return $this->_channelInfo['suggestedalias'];
  5493.         }
  5494.         if (isset($this->_channelInfo['name'])) {
  5495.             return $this->_channelInfo['name'];
  5496.         }
  5497.     }
  5498.  
  5499.     /**
  5500.      * Set the package validation object if it differs from PEAR's default
  5501.      * The class must be includeable via changing _ in the classname to path separator,
  5502.      * but no checking of this is made.
  5503.      * @param string|false pass in false to reset to the default packagename regex
  5504.      * @return boolean success
  5505.      */
  5506.     function setValidationPackage($validateclass, $version)
  5507.     {
  5508.         if (empty($validateclass)) {
  5509.             unset($this->_channelInfo['validatepackage']);
  5510.         }
  5511.         $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
  5512.         $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
  5513.     }
  5514.  
  5515.     /**
  5516.      * Add a protocol to the provides section
  5517.      * @param string protocol type
  5518.      * @param string protocol version
  5519.      * @param string protocol name, if any
  5520.      * @param string mirror name, if this is a mirror's protocol
  5521.      * @return bool
  5522.      */
  5523.     function addFunction($type, $version, $name = '', $mirror = false)
  5524.     {
  5525.         if ($mirror) {
  5526.             return $this->addMirrorFunction($mirror, $type, $version, $name);
  5527.         }
  5528.         $set = array('attribs' => array('version' => $version), '_content' => $name);
  5529.         if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
  5530.             if (!isset($this->_channelInfo['servers'])) {
  5531.                 $this->_channelInfo['servers'] = array('primary' =>
  5532.                     array($type => array()));
  5533.             } elseif (!isset($this->_channelInfo['servers']['primary'])) {
  5534.                 $this->_channelInfo['servers']['primary'] = array($type => array());
  5535.             }
  5536.             $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
  5537.             $this->_isValid = false;
  5538.             return true;
  5539.         } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
  5540.             $this->_channelInfo['servers']['primary'][$type]['function'] = array(
  5541.                 $this->_channelInfo['servers']['primary'][$type]['function']);
  5542.         }
  5543.         $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
  5544.         return true;
  5545.     }
  5546.     /**
  5547.      * Add a protocol to a mirror's provides section
  5548.      * @param string mirror name (server)
  5549.      * @param string protocol type
  5550.      * @param string protocol version
  5551.      * @param string protocol name, if any
  5552.      */
  5553.     function addMirrorFunction($mirror, $type, $version, $name = '')
  5554.     {
  5555.         $found = false;
  5556.         if (!isset($this->_channelInfo['servers']['mirror'])) {
  5557.             $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5558.                 array('mirror' => $mirror));
  5559.             return false;
  5560.         }
  5561.         $setmirror = false;
  5562.         if (isset($this->_channelInfo['servers']['mirror'][0])) {
  5563.             foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  5564.                 if ($mirror == $mir['attribs']['host']) {
  5565.                     $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  5566.                     break;
  5567.                 }
  5568.             }
  5569.         } else {
  5570.             if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  5571.                 $setmirror = &$this->_channelInfo['servers']['mirror'];
  5572.             }
  5573.         }
  5574.         if (!$setmirror) {
  5575.             $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5576.                 array('mirror' => $mirror));
  5577.             return false;
  5578.         }
  5579.         $set = array('attribs' => array('version' => $version), '_content' => $name);
  5580.         if (!isset($setmirror[$type]['function'])) {
  5581.             $setmirror[$type]['function'] = $set;
  5582.             $this->_isValid = false;
  5583.             return true;
  5584.         } elseif (!isset($setmirror[$type]['function'][0])) {
  5585.             $setmirror[$type]['function'] = array($setmirror[$type]['function']);
  5586.         }
  5587.         $setmirror[$type]['function'][] = $set;
  5588.         $this->_isValid = false;
  5589.         return true;
  5590.     }
  5591.  
  5592.     /**
  5593.      * @param string Resource Type this url links to
  5594.      * @param string URL
  5595.      * @param string|false mirror name, if this is not a primary server REST base URL
  5596.      */
  5597.     function setBaseURL($resourceType, $url, $mirror = false)
  5598.     {
  5599.         if ($mirror) {
  5600.             $found = false;
  5601.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  5602.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  5603.                     array('mirror' => $mirror));
  5604.                 return false;
  5605.             }
  5606.             $setmirror = false;
  5607.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  5608.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  5609.                     if ($mirror == $mir['attribs']['host']) {
  5610.                         $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  5611.                         break;
  5612.                     }
  5613.                 }
  5614.             } else {
  5615.                 if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  5616.                     $setmirror = &$this->_channelInfo['servers']['mirror'];
  5617.                 }
  5618.             }
  5619.         } else {
  5620.             $setmirror = &$this->_channelInfo['servers']['primary'];
  5621.         }
  5622.         $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
  5623.         if (!isset($setmirror['rest'])) {
  5624.             $setmirror['rest'] = array();
  5625.         }
  5626.         if (!isset($setmirror['rest']['baseurl'])) {
  5627.             $setmirror['rest']['baseurl'] = $set;
  5628.             $this->_isValid = false;
  5629.             return true;
  5630.         } elseif (!isset($setmirror['rest']['baseurl'][0])) {
  5631.             $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
  5632.         }
  5633.         foreach ($setmirror['rest']['baseurl'] as $i => $url) {
  5634.             if ($url['attribs']['type'] == $resourceType) {
  5635.                 $this->_isValid = false;
  5636.                 $setmirror['rest']['baseurl'][$i] = $set;
  5637.                 return true;
  5638.             }
  5639.         }
  5640.         $setmirror['rest']['baseurl'][] = $set;
  5641.         $this->_isValid = false;
  5642.         return true;
  5643.     }
  5644.  
  5645.     /**
  5646.      * @param string mirror server
  5647.      * @param int mirror http port
  5648.      * @return boolean
  5649.      */
  5650.     function addMirror($server, $port = null)
  5651.     {
  5652.         if ($this->_channelInfo['name'] == '__uri') {
  5653.             return false; // the __uri channel cannot have mirrors by definition
  5654.         }
  5655.         $set = array('attribs' => array('host' => $server));
  5656.         if (is_numeric($port)) {
  5657.             $set['attribs']['port'] = $port;
  5658.         }
  5659.         if (!isset($this->_channelInfo['servers']['mirror'])) {
  5660.             $this->_channelInfo['servers']['mirror'] = $set;
  5661.             return true;
  5662.         } else {
  5663.             if (!isset($this->_channelInfo['servers']['mirror'][0])) {
  5664.                 $this->_channelInfo['servers']['mirror'] =
  5665.                     array($this->_channelInfo['servers']['mirror']);
  5666.             }
  5667.         }
  5668.         $this->_channelInfo['servers']['mirror'][] = $set;
  5669.         return true;
  5670.     }
  5671.  
  5672.     /**
  5673.      * Retrieve the name of the validation package for this channel
  5674.      * @return string|false
  5675.      */
  5676.     function getValidationPackage()
  5677.     {
  5678.         if (!$this->_isValid && !$this->validate()) {
  5679.             return false;
  5680.         }
  5681.         if (!isset($this->_channelInfo['validatepackage'])) {
  5682.             return array('attribs' => array('version' => 'default'),
  5683.                 '_content' => 'PEAR_Validate');
  5684.         }
  5685.         return $this->_channelInfo['validatepackage'];
  5686.     }
  5687.  
  5688.     /**
  5689.      * Retrieve the object that can be used for custom validation
  5690.      * @param string|false the name of the package to validate.  If the package is
  5691.      *                     the channel validation package, PEAR_Validate is returned
  5692.      * @return PEAR_Validate|false false is returned if the validation package
  5693.      *         cannot be located
  5694.      */
  5695.     function &getValidationObject($package = false)
  5696.     {
  5697.         if (!class_exists('PEAR_Validate')) {
  5698.             require_once 'phar://go-pear.phar/PEAR/Validate.php';
  5699.         }
  5700.         if (!$this->_isValid) {
  5701.             if (!$this->validate()) {
  5702.                 $a = false;
  5703.                 return $a;
  5704.             }
  5705.         }
  5706.         if (isset($this->_channelInfo['validatepackage'])) {
  5707.             if ($package == $this->_channelInfo['validatepackage']) {
  5708.                 // channel validation packages are always validated by PEAR_Validate
  5709.                 $val = &new PEAR_Validate;
  5710.                 return $val;
  5711.             }
  5712.             if (!class_exists(str_replace('.', '_',
  5713.                   $this->_channelInfo['validatepackage']['_content']))) {
  5714.                 if ($this->isIncludeable(str_replace('_', '/',
  5715.                       $this->_channelInfo['validatepackage']['_content']) . '.php')) {
  5716.                     include_once str_replace('_', '/',
  5717.                         $this->_channelInfo['validatepackage']['_content']) . '.php';
  5718.                     $vclass = str_replace('.', '_',
  5719.                         $this->_channelInfo['validatepackage']['_content']);
  5720.                     $val = &new $vclass;
  5721.                 } else {
  5722.                     $a = false;
  5723.                     return $a;
  5724.                 }
  5725.             } else {
  5726.                 $vclass = str_replace('.', '_',
  5727.                     $this->_channelInfo['validatepackage']['_content']);
  5728.                 $val = &new $vclass;
  5729.             }
  5730.         } else {
  5731.             $val = &new PEAR_Validate;
  5732.         }
  5733.         return $val;
  5734.     }
  5735.  
  5736.     function isIncludeable($path)
  5737.     {
  5738.         $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
  5739.         foreach ($possibilities as $dir) {
  5740.             if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
  5741.                   && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
  5742.                 return true;
  5743.             }
  5744.         }
  5745.         return false;
  5746.     }
  5747.  
  5748.     /**
  5749.      * This function is used by the channel updater and retrieves a value set by
  5750.      * the registry, or the current time if it has not been set
  5751.      * @return string
  5752.      */
  5753.     function lastModified()
  5754.     {
  5755.         if (isset($this->_channelInfo['_lastmodified'])) {
  5756.             return $this->_channelInfo['_lastmodified'];
  5757.         }
  5758.         return time();
  5759.     }
  5760. }
  5761. ?>
  5762. <?php
  5763. /**
  5764.  * PEAR_ChannelFile_Parser for parsing channel.xml
  5765.  *
  5766.  * PHP versions 4 and 5
  5767.  *
  5768.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  5769.  * that is available through the world-wide-web at the following URI:
  5770.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  5771.  * the PHP License and are unable to obtain it through the web, please
  5772.  * send a note to license@php.net so we can mail you a copy immediately.
  5773.  *
  5774.  * @category   pear
  5775.  * @package    PEAR
  5776.  * @author     Greg Beaver <cellog@php.net>
  5777.  * @copyright  1997-2006 The PHP Group
  5778.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  5779.  * @version    CVS: $Id: Parser.php,v 1.4 2006/01/06 04:47:36 cellog Exp $
  5780.  * @link       http://pear.php.net/package/PEAR
  5781.  * @since      File available since Release 1.4.0a1
  5782.  */
  5783.  
  5784. /**
  5785.  * base xml parser class
  5786.  */
  5787. require_once 'phar://go-pear.phar/PEAR/XMLParser.php';
  5788. require_once 'phar://go-pear.phar/PEAR/ChannelFile.php';
  5789. /**
  5790.  * Parser for channel.xml
  5791.  * @category   pear
  5792.  * @package    PEAR
  5793.  * @author     Greg Beaver <cellog@php.net>
  5794.  * @copyright  1997-2006 The PHP Group
  5795.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  5796.  * @version    Release: @package_version@
  5797.  * @link       http://pear.php.net/package/PEAR
  5798.  * @since      Class available since Release 1.4.0a1
  5799.  */
  5800. class PEAR_ChannelFile_Parser extends PEAR_XMLParser
  5801. {
  5802.     var $_config;
  5803.     var $_logger;
  5804.     var $_registry;
  5805.  
  5806.     function setConfig(&$c)
  5807.     {
  5808.         $this->_config = &$c;
  5809.         $this->_registry = &$c->getRegistry();
  5810.     }
  5811.  
  5812.     function setLogger(&$l)
  5813.     {
  5814.         $this->_logger = &$l;
  5815.     }
  5816.  
  5817.     function parse($data, $file)
  5818.     {
  5819.         if (PEAR::isError($err = parent::parse($data, $file))) {
  5820.             return $err;
  5821.         }
  5822.         $ret = new PEAR_ChannelFile;
  5823.         $ret->setConfig($this->_config);
  5824.         if (isset($this->_logger)) {
  5825.             $ret->setLogger($this->_logger);
  5826.         }
  5827.         $ret->fromArray($this->_unserializedData);
  5828.         // make sure the filelist is in the easy to read format needed
  5829.         $ret->flattenFilelist();
  5830.         $ret->setPackagefile($file, $archive);
  5831.         return $ret;
  5832.     }
  5833. }
  5834. ?><?php
  5835. /**
  5836.  * PEAR_Command, command pattern class
  5837.  *
  5838.  * PHP versions 4 and 5
  5839.  *
  5840.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  5841.  * that is available through the world-wide-web at the following URI:
  5842.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  5843.  * the PHP License and are unable to obtain it through the web, please
  5844.  * send a note to license@php.net so we can mail you a copy immediately.
  5845.  *
  5846.  * @category   pear
  5847.  * @package    PEAR
  5848.  * @author     Stig Bakken <ssb@php.net>
  5849.  * @author     Greg Beaver <cellog@php.net>
  5850.  * @copyright  1997-2006 The PHP Group
  5851.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  5852.  * @version    CVS: $Id: Command.php,v 1.37 2006/06/09 00:17:50 pajoye Exp $
  5853.  * @link       http://pear.php.net/package/PEAR
  5854.  * @since      File available since Release 0.1
  5855.  */
  5856.  
  5857. /**
  5858.  * Needed for error handling
  5859.  */
  5860. require_once 'phar://go-pear.phar/PEAR.php';
  5861. require_once 'phar://go-pear.phar/PEAR/Frontend.php';
  5862. require_once 'phar://go-pear.phar/PEAR/XMLParser.php';
  5863.  
  5864. /**
  5865.  * List of commands and what classes they are implemented in.
  5866.  * @var array command => implementing class
  5867.  */
  5868. $GLOBALS['_PEAR_Command_commandlist'] = array();
  5869.  
  5870. /**
  5871.  * List of commands and their descriptions
  5872.  * @var array command => description
  5873.  */
  5874. $GLOBALS['_PEAR_Command_commanddesc'] = array();
  5875.  
  5876. /**
  5877.  * List of shortcuts to common commands.
  5878.  * @var array shortcut => command
  5879.  */
  5880. $GLOBALS['_PEAR_Command_shortcuts'] = array();
  5881.  
  5882. /**
  5883.  * Array of command objects
  5884.  * @var array class => object
  5885.  */
  5886. $GLOBALS['_PEAR_Command_objects'] = array();
  5887.  
  5888. /**
  5889.  * PEAR command class, a simple factory class for administrative
  5890.  * commands.
  5891.  *
  5892.  * How to implement command classes:
  5893.  *
  5894.  * - The class must be called PEAR_Command_Nnn, installed in the
  5895.  *   "PEAR/Common" subdir, with a method called getCommands() that
  5896.  *   returns an array of the commands implemented by the class (see
  5897.  *   PEAR/Command/Install.php for an example).
  5898.  *
  5899.  * - The class must implement a run() function that is called with three
  5900.  *   params:
  5901.  *
  5902.  *    (string) command name
  5903.  *    (array)  assoc array with options, freely defined by each
  5904.  *             command, for example:
  5905.  *             array('force' => true)
  5906.  *    (array)  list of the other parameters
  5907.  *
  5908.  *   The run() function returns a PEAR_CommandResponse object.  Use
  5909.  *   these methods to get information:
  5910.  *
  5911.  *    int getStatus()   Returns PEAR_COMMAND_(SUCCESS|FAILURE|PARTIAL)
  5912.  *                      *_PARTIAL means that you need to issue at least
  5913.  *                      one more command to complete the operation
  5914.  *                      (used for example for validation steps).
  5915.  *
  5916.  *    string getMessage()  Returns a message for the user.  Remember,
  5917.  *                         no HTML or other interface-specific markup.
  5918.  *
  5919.  *   If something unexpected happens, run() returns a PEAR error.
  5920.  *
  5921.  * - DON'T OUTPUT ANYTHING! Return text for output instead.
  5922.  *
  5923.  * - DON'T USE HTML! The text you return will be used from both Gtk,
  5924.  *   web and command-line interfaces, so for now, keep everything to
  5925.  *   plain text.
  5926.  *
  5927.  * - DON'T USE EXIT OR DIE! Always use pear errors.  From static
  5928.  *   classes do PEAR::raiseError(), from other classes do
  5929.  *   $this->raiseError().
  5930.  * @category   pear
  5931.  * @package    PEAR
  5932.  * @author     Stig Bakken <ssb@php.net>
  5933.  * @author     Greg Beaver <cellog@php.net>
  5934.  * @copyright  1997-2006 The PHP Group
  5935.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  5936.  * @version    Release: @package_version@
  5937.  * @link       http://pear.php.net/package/PEAR
  5938.  * @since      Class available since Release 0.1
  5939.  */
  5940. class PEAR_Command
  5941. {
  5942.     // {{{ factory()
  5943.  
  5944.     /**
  5945.      * Get the right object for executing a command.
  5946.      *
  5947.      * @param string $command The name of the command
  5948.      * @param object $config  Instance of PEAR_Config object
  5949.      *
  5950.      * @return object the command object or a PEAR error
  5951.      *
  5952.      * @access public
  5953.      * @static
  5954.      */
  5955.     function &factory($command, &$config)
  5956.     {
  5957.         if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  5958.             PEAR_Command::registerCommands();
  5959.         }
  5960.         if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  5961.             $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  5962.         }
  5963.         if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  5964.             $a = PEAR::raiseError("unknown command `$command'");
  5965.             return $a;
  5966.         }
  5967.         $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
  5968.         if (!class_exists($class)) {
  5969.             require_once $GLOBALS['_PEAR_Command_objects'][$class];
  5970.         }
  5971.         if (!class_exists($class)) {
  5972.             $a = PEAR::raiseError("unknown command `$command'");
  5973.             return $a;
  5974.         }
  5975.         $ui =& PEAR_Command::getFrontendObject();
  5976.         $obj = &new $class($ui, $config);
  5977.         return $obj;
  5978.     }
  5979.  
  5980.     // }}}
  5981.     // {{{ & getObject()
  5982.     function &getObject($command)
  5983.     {
  5984.         $class = $GLOBALS['_PEAR_Command_commandlist'][$command];
  5985.         if (!class_exists($class)) {
  5986.             require_once $GLOBALS['_PEAR_Command_objects'][$class];
  5987.         }
  5988.         if (!class_exists($class)) {
  5989.             return PEAR::raiseError("unknown command `$command'");
  5990.         }
  5991.         $ui =& PEAR_Command::getFrontendObject();
  5992.         $config = &PEAR_Config::singleton();
  5993.         $obj = &new $class($ui, $config);
  5994.         return $obj;
  5995.     }
  5996.  
  5997.     // }}}
  5998.     // {{{ & getFrontendObject()
  5999.  
  6000.     /**
  6001.      * Get instance of frontend object.
  6002.      *
  6003.      * @return object|PEAR_Error
  6004.      * @static
  6005.      */
  6006.     function &getFrontendObject()
  6007.     {
  6008.         $a = &PEAR_Frontend::singleton();
  6009.         return $a;
  6010.     }
  6011.  
  6012.     // }}}
  6013.     // {{{ & setFrontendClass()
  6014.  
  6015.     /**
  6016.      * Load current frontend class.
  6017.      *
  6018.      * @param string $uiclass Name of class implementing the frontend
  6019.      *
  6020.      * @return object the frontend object, or a PEAR error
  6021.      * @static
  6022.      */
  6023.     function &setFrontendClass($uiclass)
  6024.     {
  6025.         $a = &PEAR_Frontend::setFrontendClass($uiclass);
  6026.         return $a;
  6027.     }
  6028.  
  6029.     // }}}
  6030.     // {{{ setFrontendType()
  6031.  
  6032.     /**
  6033.      * Set current frontend.
  6034.      *
  6035.      * @param string $uitype Name of the frontend type (for example "CLI")
  6036.      *
  6037.      * @return object the frontend object, or a PEAR error
  6038.      * @static
  6039.      */
  6040.     function setFrontendType($uitype)
  6041.     {
  6042.         $uiclass = 'PEAR_Frontend_' . $uitype;
  6043.         return PEAR_Command::setFrontendClass($uiclass);
  6044.     }
  6045.  
  6046.     // }}}
  6047.     // {{{ registerCommands()
  6048.  
  6049.     /**
  6050.      * Scan through the Command directory looking for classes
  6051.      * and see what commands they implement.
  6052.      *
  6053.      * @param bool   (optional) if FALSE (default), the new list of
  6054.      *               commands should replace the current one.  If TRUE,
  6055.      *               new entries will be merged with old.
  6056.      *
  6057.      * @param string (optional) where (what directory) to look for
  6058.      *               classes, defaults to the Command subdirectory of
  6059.      *               the directory from where this file (__FILE__) is
  6060.      *               included.
  6061.      *
  6062.      * @return bool TRUE on success, a PEAR error on failure
  6063.      *
  6064.      * @access public
  6065.      * @static
  6066.      */
  6067.     function registerCommands($merge = false, $dir = null)
  6068.     {
  6069.         $parser = new PEAR_XMLParser;
  6070.         if ($dir === null) {
  6071.             $dir = dirname(__FILE__) . '/Command';
  6072.         }
  6073.         if (!is_dir($dir)) {
  6074.             return PEAR::raiseError("registerCommands: opendir($dir) '$dir' does not exist or is not a directory");
  6075.         }
  6076.         $dp = @opendir($dir);
  6077.         if (empty($dp)) {
  6078.             return PEAR::raiseError("registerCommands: opendir($dir) failed");
  6079.         }
  6080.         if (!$merge) {
  6081.             $GLOBALS['_PEAR_Command_commandlist'] = array();
  6082.         }
  6083.         while ($entry = readdir($dp)) {
  6084.             if ($entry{0} == '.' || substr($entry, -4) != '.xml') {
  6085.                 continue;
  6086.             }
  6087.             $class = "PEAR_Command_".substr($entry, 0, -4);
  6088.             $file = "$dir/$entry";
  6089.             $parser->parse(file_get_contents($file));
  6090.             $implements = $parser->getData();
  6091.             // List of commands
  6092.             if (empty($GLOBALS['_PEAR_Command_objects'][$class])) {
  6093.                 $GLOBALS['_PEAR_Command_objects'][$class] = "$dir/" . substr($entry, 0, -4) .
  6094.                     '.php';
  6095.             }
  6096.             foreach ($implements as $command => $desc) {
  6097.                 if ($command == 'attribs') {
  6098.                     continue;
  6099.                 }
  6100.                 if (isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  6101.                     return PEAR::raiseError('Command "' . $command . '" already registered in ' .
  6102.                         'class "' . $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
  6103.                 }
  6104.                 $GLOBALS['_PEAR_Command_commandlist'][$command] = $class;
  6105.                 $GLOBALS['_PEAR_Command_commanddesc'][$command] = $desc['summary'];
  6106.                 if (isset($desc['shortcut'])) {
  6107.                     $shortcut = $desc['shortcut'];
  6108.                     if (isset($GLOBALS['_PEAR_Command_shortcuts'][$shortcut])) {
  6109.                         return PEAR::raiseError('Command shortcut "' . $shortcut . '" already ' .
  6110.                             'registered to command "' . $command . '" in class "' .
  6111.                             $GLOBALS['_PEAR_Command_commandlist'][$command] . '"');
  6112.                     }
  6113.                     $GLOBALS['_PEAR_Command_shortcuts'][$shortcut] = $command;
  6114.                 }
  6115.                 if (isset($desc['options']) && $desc['options']) {
  6116.                     foreach ($desc['options'] as $oname => $option) {
  6117.                         if (isset($option['shortopt']) && strlen($option['shortopt']) > 1) {
  6118.                             return PEAR::raiseError('Option "' . $oname . '" short option "' .
  6119.                                 $option['shortopt'] . '" must be ' .
  6120.                                 'only 1 character in Command "' . $command . '" in class "' .
  6121.                                 $class . '"');
  6122.                         }
  6123.                     }
  6124.                 }
  6125.             }
  6126.         }
  6127.         ksort($GLOBALS['_PEAR_Command_shortcuts']);
  6128.         ksort($GLOBALS['_PEAR_Command_commandlist']);
  6129.         @closedir($dp);
  6130.         return true;
  6131.     }
  6132.  
  6133.     // }}}
  6134.     // {{{ getCommands()
  6135.  
  6136.     /**
  6137.      * Get the list of currently supported commands, and what
  6138.      * classes implement them.
  6139.      *
  6140.      * @return array command => implementing class
  6141.      *
  6142.      * @access public
  6143.      * @static
  6144.      */
  6145.     function getCommands()
  6146.     {
  6147.         if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  6148.             PEAR_Command::registerCommands();
  6149.         }
  6150.         return $GLOBALS['_PEAR_Command_commandlist'];
  6151.     }
  6152.  
  6153.     // }}}
  6154.     // {{{ getShortcuts()
  6155.  
  6156.     /**
  6157.      * Get the list of command shortcuts.
  6158.      *
  6159.      * @return array shortcut => command
  6160.      *
  6161.      * @access public
  6162.      * @static
  6163.      */
  6164.     function getShortcuts()
  6165.     {
  6166.         if (empty($GLOBALS['_PEAR_Command_shortcuts'])) {
  6167.             PEAR_Command::registerCommands();
  6168.         }
  6169.         return $GLOBALS['_PEAR_Command_shortcuts'];
  6170.     }
  6171.  
  6172.     // }}}
  6173.     // {{{ getGetoptArgs()
  6174.  
  6175.     /**
  6176.      * Compiles arguments for getopt.
  6177.      *
  6178.      * @param string $command     command to get optstring for
  6179.      * @param string $short_args  (reference) short getopt format
  6180.      * @param array  $long_args   (reference) long getopt format
  6181.      *
  6182.      * @return void
  6183.      *
  6184.      * @access public
  6185.      * @static
  6186.      */
  6187.     function getGetoptArgs($command, &$short_args, &$long_args)
  6188.     {
  6189.         if (empty($GLOBALS['_PEAR_Command_commandlist'])) {
  6190.             PEAR_Command::registerCommands();
  6191.         }
  6192.         if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  6193.             $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  6194.         }
  6195.         if (!isset($GLOBALS['_PEAR_Command_commandlist'][$command])) {
  6196.             return null;
  6197.         }
  6198.         $obj = &PEAR_Command::getObject($command);
  6199.         return $obj->getGetoptArgs($command, $short_args, $long_args);
  6200.     }
  6201.  
  6202.     // }}}
  6203.     // {{{ getDescription()
  6204.  
  6205.     /**
  6206.      * Get description for a command.
  6207.      *
  6208.      * @param  string $command Name of the command
  6209.      *
  6210.      * @return string command description
  6211.      *
  6212.      * @access public
  6213.      * @static
  6214.      */
  6215.     function getDescription($command)
  6216.     {
  6217.         if (!isset($GLOBALS['_PEAR_Command_commanddesc'][$command])) {
  6218.             return null;
  6219.         }
  6220.         return $GLOBALS['_PEAR_Command_commanddesc'][$command];
  6221.     }
  6222.  
  6223.     // }}}
  6224.     // {{{ getHelp()
  6225.  
  6226.     /**
  6227.      * Get help for command.
  6228.      *
  6229.      * @param string $command Name of the command to return help for
  6230.      *
  6231.      * @access public
  6232.      * @static
  6233.      */
  6234.     function getHelp($command)
  6235.     {
  6236.         $cmds = PEAR_Command::getCommands();
  6237.         if (isset($GLOBALS['_PEAR_Command_shortcuts'][$command])) {
  6238.             $command = $GLOBALS['_PEAR_Command_shortcuts'][$command];
  6239.         }
  6240.         if (isset($cmds[$command])) {
  6241.             $obj = &PEAR_Command::getObject($command);
  6242.             return $obj->getHelp($command);
  6243.         }
  6244.         return false;
  6245.     }
  6246.     // }}}
  6247. }
  6248.  
  6249. ?>
  6250. <?php
  6251. /**
  6252.  * PEAR_Command_Common base class
  6253.  *
  6254.  * PHP versions 4 and 5
  6255.  *
  6256.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  6257.  * that is available through the world-wide-web at the following URI:
  6258.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  6259.  * the PHP License and are unable to obtain it through the web, please
  6260.  * send a note to license@php.net so we can mail you a copy immediately.
  6261.  *
  6262.  * @category   pear
  6263.  * @package    PEAR
  6264.  * @author     Stig Bakken <ssb@php.net>
  6265.  * @author     Greg Beaver <cellog@php.net>
  6266.  * @copyright  1997-2006 The PHP Group
  6267.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6268.  * @version    CVS: $Id: Common.php,v 1.35 2006/06/08 22:25:18 pajoye Exp $
  6269.  * @link       http://pear.php.net/package/PEAR
  6270.  * @since      File available since Release 0.1
  6271.  */
  6272.  
  6273. /**
  6274.  * base class
  6275.  */
  6276. require_once 'phar://go-pear.phar/PEAR.php';
  6277.  
  6278. /**
  6279.  * PEAR commands base class
  6280.  *
  6281.  * @category   pear
  6282.  * @package    PEAR
  6283.  * @author     Stig Bakken <ssb@php.net>
  6284.  * @author     Greg Beaver <cellog@php.net>
  6285.  * @copyright  1997-2006 The PHP Group
  6286.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6287.  * @version    Release: @package_version@
  6288.  * @link       http://pear.php.net/package/PEAR
  6289.  * @since      Class available since Release 0.1
  6290.  */
  6291. class PEAR_Command_Common extends PEAR
  6292. {
  6293.     // {{{ properties
  6294.  
  6295.     /**
  6296.      * PEAR_Config object used to pass user system and configuration
  6297.      * on when executing commands
  6298.      *
  6299.      * @var PEAR_Config
  6300.      */
  6301.     var $config;
  6302.     /**
  6303.      * @var PEAR_Registry
  6304.      * @access protected
  6305.      */
  6306.     var $_registry;
  6307.  
  6308.     /**
  6309.      * User Interface object, for all interaction with the user.
  6310.      * @var object
  6311.      */
  6312.     var $ui;
  6313.  
  6314.     var $_deps_rel_trans = array(
  6315.                                  'lt' => '<',
  6316.                                  'le' => '<=',
  6317.                                  'eq' => '=',
  6318.                                  'ne' => '!=',
  6319.                                  'gt' => '>',
  6320.                                  'ge' => '>=',
  6321.                                  'has' => '=='
  6322.                                  );
  6323.  
  6324.     var $_deps_type_trans = array(
  6325.                                   'pkg' => 'package',
  6326.                                   'ext' => 'extension',
  6327.                                   'php' => 'PHP',
  6328.                                   'prog' => 'external program',
  6329.                                   'ldlib' => 'external library for linking',
  6330.                                   'rtlib' => 'external runtime library',
  6331.                                   'os' => 'operating system',
  6332.                                   'websrv' => 'web server',
  6333.                                   'sapi' => 'SAPI backend'
  6334.                                   );
  6335.  
  6336.     // }}}
  6337.     // {{{ constructor
  6338.  
  6339.     /**
  6340.      * PEAR_Command_Common constructor.
  6341.      *
  6342.      * @access public
  6343.      */
  6344.     function PEAR_Command_Common(&$ui, &$config)
  6345.     {
  6346.         parent::PEAR();
  6347.         $this->config = &$config;
  6348.         $this->ui = &$ui;
  6349.     }
  6350.  
  6351.     // }}}
  6352.  
  6353.     // {{{ getCommands()
  6354.  
  6355.     /**
  6356.      * Return a list of all the commands defined by this class.
  6357.      * @return array list of commands
  6358.      * @access public
  6359.      */
  6360.     function getCommands()
  6361.     {
  6362.         $ret = array();
  6363.         foreach (array_keys($this->commands) as $command) {
  6364.             $ret[$command] = $this->commands[$command]['summary'];
  6365.         }
  6366.         return $ret;
  6367.     }
  6368.  
  6369.     // }}}
  6370.     // {{{ getShortcuts()
  6371.  
  6372.     /**
  6373.      * Return a list of all the command shortcuts defined by this class.
  6374.      * @return array shortcut => command
  6375.      * @access public
  6376.      */
  6377.     function getShortcuts()
  6378.     {
  6379.         $ret = array();
  6380.         foreach (array_keys($this->commands) as $command) {
  6381.             if (isset($this->commands[$command]['shortcut'])) {
  6382.                 $ret[$this->commands[$command]['shortcut']] = $command;
  6383.             }
  6384.         }
  6385.         return $ret;
  6386.     }
  6387.  
  6388.     // }}}
  6389.     // {{{ getOptions()
  6390.  
  6391.     function getOptions($command)
  6392.     {
  6393.         $shortcuts = $this->getShortcuts();
  6394.         if (isset($shortcuts[$command])) {
  6395.             $command = $shortcuts[$command];
  6396.         }
  6397.         if (isset($this->commands[$command]) &&
  6398.               isset($this->commands[$command]['options'])) {
  6399.             return $this->commands[$command]['options'];
  6400.         } else {
  6401.             return null;
  6402.         }
  6403.     }
  6404.  
  6405.     // }}}
  6406.     // {{{ getGetoptArgs()
  6407.  
  6408.     function getGetoptArgs($command, &$short_args, &$long_args)
  6409.     {
  6410.         $short_args = "";
  6411.         $long_args = array();
  6412.         if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
  6413.             return;
  6414.         }
  6415.         reset($this->commands[$command]['options']);
  6416.         while (list($option, $info) = each($this->commands[$command]['options'])) {
  6417.             $larg = $sarg = '';
  6418.             if (isset($info['arg'])) {
  6419.                 if ($info['arg']{0} == '(') {
  6420.                     $larg = '==';
  6421.                     $sarg = '::';
  6422.                     $arg = substr($info['arg'], 1, -1);
  6423.                 } else {
  6424.                     $larg = '=';
  6425.                     $sarg = ':';
  6426.                     $arg = $info['arg'];
  6427.                 }
  6428.             }
  6429.             if (isset($info['shortopt'])) {
  6430.                 $short_args .= $info['shortopt'] . $sarg;
  6431.             }
  6432.             $long_args[] = $option . $larg;
  6433.         }
  6434.     }
  6435.  
  6436.     // }}}
  6437.     // {{{ getHelp()
  6438.     /**
  6439.     * Returns the help message for the given command
  6440.     *
  6441.     * @param string $command The command
  6442.     * @return mixed A fail string if the command does not have help or
  6443.     *               a two elements array containing [0]=>help string,
  6444.     *               [1]=> help string for the accepted cmd args
  6445.     */
  6446.     function getHelp($command)
  6447.     {
  6448.         $config = &PEAR_Config::singleton();
  6449.         if (!isset($this->commands[$command])) {
  6450.             return "No such command \"$command\"";
  6451.         }
  6452.         $help = null;
  6453.         if (isset($this->commands[$command]['doc'])) {
  6454.             $help = $this->commands[$command]['doc'];
  6455.         }
  6456.         if (empty($help)) {
  6457.             // XXX (cox) Fallback to summary if there is no doc (show both?)
  6458.             if (!isset($this->commands[$command]['summary'])) {
  6459.                 return "No help for command \"$command\"";
  6460.             }
  6461.             $help = $this->commands[$command]['summary'];
  6462.         }
  6463.         if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) {
  6464.             foreach($matches[0] as $k => $v) {
  6465.                 $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
  6466.             }
  6467.         }
  6468.         return array($help, $this->getHelpArgs($command));
  6469.     }
  6470.  
  6471.     // }}}
  6472.     // {{{ getHelpArgs()
  6473.     /**
  6474.     * Returns the help for the accepted arguments of a command
  6475.     *
  6476.     * @param  string $command
  6477.     * @return string The help string
  6478.     */
  6479.     function getHelpArgs($command)
  6480.     {
  6481.         if (isset($this->commands[$command]['options']) &&
  6482.             count($this->commands[$command]['options']))
  6483.         {
  6484.             $help = "Options:\n";
  6485.             foreach ($this->commands[$command]['options'] as $k => $v) {
  6486.                 if (isset($v['arg'])) {
  6487.                     if ($v['arg'][0] == '(') {
  6488.                         $arg = substr($v['arg'], 1, -1);
  6489.                         $sapp = " [$arg]";
  6490.                         $lapp = "[=$arg]";
  6491.                     } else {
  6492.                         $sapp = " $v[arg]";
  6493.                         $lapp = "=$v[arg]";
  6494.                     }
  6495.                 } else {
  6496.                     $sapp = $lapp = "";
  6497.                 }
  6498.                 if (isset($v['shortopt'])) {
  6499.                     $s = $v['shortopt'];
  6500.                     $help .= "  -$s$sapp, --$k$lapp\n";
  6501.                 } else {
  6502.                     $help .= "  --$k$lapp\n";
  6503.                 }
  6504.                 $p = "        ";
  6505.                 $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
  6506.                 $help .= "        $doc\n";
  6507.             }
  6508.             return $help;
  6509.         }
  6510.         return null;
  6511.     }
  6512.  
  6513.     // }}}
  6514.     // {{{ run()
  6515.  
  6516.     function run($command, $options, $params)
  6517.     {
  6518.         if (empty($this->commands[$command]['function'])) {
  6519.             // look for shortcuts
  6520.             foreach (array_keys($this->commands) as $cmd) {
  6521.                 if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
  6522.                     if (empty($this->commands[$cmd]['function'])) {
  6523.                         return $this->raiseError("unknown command `$command'");
  6524.                     } else {
  6525.                         $func = $this->commands[$cmd]['function'];
  6526.                     }
  6527.                     $command = $cmd;
  6528.                     break;
  6529.                 }
  6530.             }
  6531.         } else {
  6532.             $func = $this->commands[$command]['function'];
  6533.         }
  6534.         return $this->$func($command, $options, $params);
  6535.     }
  6536.  
  6537.     // }}}
  6538. }
  6539.  
  6540. ?>
  6541. <?php
  6542. /**
  6543.  * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
  6544.  *
  6545.  * PHP versions 4 and 5
  6546.  *
  6547.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  6548.  * that is available through the world-wide-web at the following URI:
  6549.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  6550.  * the PHP License and are unable to obtain it through the web, please
  6551.  * send a note to license@php.net so we can mail you a copy immediately.
  6552.  *
  6553.  * @category   pear
  6554.  * @package    PEAR
  6555.  * @author     Stig Bakken <ssb@php.net>
  6556.  * @author     Greg Beaver <cellog@php.net>
  6557.  * @copyright  1997-2006 The PHP Group
  6558.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6559.  * @version    CVS: $Id: Install.php,v 1.120 2006/10/22 18:20:58 cellog Exp $
  6560.  * @link       http://pear.php.net/package/PEAR
  6561.  * @since      File available since Release 0.1
  6562.  */
  6563.  
  6564. /**
  6565.  * base class
  6566.  */
  6567. require_once 'phar://go-pear.phar/PEAR/Command/Common.php';
  6568.  
  6569. /**
  6570.  * PEAR commands for installation or deinstallation/upgrading of
  6571.  * packages.
  6572.  *
  6573.  * @category   pear
  6574.  * @package    PEAR
  6575.  * @author     Stig Bakken <ssb@php.net>
  6576.  * @author     Greg Beaver <cellog@php.net>
  6577.  * @copyright  1997-2006 The PHP Group
  6578.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  6579.  * @version    Release: @package_version@
  6580.  * @link       http://pear.php.net/package/PEAR
  6581.  * @since      Class available since Release 0.1
  6582.  */
  6583. class PEAR_Command_Install extends PEAR_Command_Common
  6584. {
  6585.     // {{{ properties
  6586.  
  6587.     var $commands = array(
  6588.         'install' => array(
  6589.             'summary' => 'Install Package',
  6590.             'function' => 'doInstall',
  6591.             'shortcut' => 'i',
  6592.             'options' => array(
  6593.                 'force' => array(
  6594.                     'shortopt' => 'f',
  6595.                     'doc' => 'will overwrite newer installed packages',
  6596.                     ),
  6597.                 'loose' => array(
  6598.                     'shortopt' => 'l',
  6599.                     'doc' => 'do not check for recommended dependency version',
  6600.                     ),
  6601.                 'nodeps' => array(
  6602.                     'shortopt' => 'n',
  6603.                     'doc' => 'ignore dependencies, install anyway',
  6604.                     ),
  6605.                 'register-only' => array(
  6606.                     'shortopt' => 'r',
  6607.                     'doc' => 'do not install files, only register the package as installed',
  6608.                     ),
  6609.                 'soft' => array(
  6610.                     'shortopt' => 's',
  6611.                     'doc' => 'soft install, fail silently, or upgrade if already installed',
  6612.                     ),
  6613.                 'nobuild' => array(
  6614.                     'shortopt' => 'B',
  6615.                     'doc' => 'don\'t build C extensions',
  6616.                     ),
  6617.                 'nocompress' => array(
  6618.                     'shortopt' => 'Z',
  6619.                     'doc' => 'request uncompressed files when downloading',
  6620.                     ),
  6621.                 'installroot' => array(
  6622.                     'shortopt' => 'R',
  6623.                     'arg' => 'DIR',
  6624.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  6625.                     ),
  6626.                 'packagingroot' => array(
  6627.                     'shortopt' => 'P',
  6628.                     'arg' => 'DIR',
  6629.                     'doc' => 'root directory used when packaging files, like RPM packaging',
  6630.                     ),
  6631.                 'ignore-errors' => array(
  6632.                     'doc' => 'force install even if there were errors',
  6633.                     ),
  6634.                 'alldeps' => array(
  6635.                     'shortopt' => 'a',
  6636.                     'doc' => 'install all required and optional dependencies',
  6637.                     ),
  6638.                 'onlyreqdeps' => array(
  6639.                     'shortopt' => 'o',
  6640.                     'doc' => 'install all required dependencies',
  6641.                     ),
  6642.                 'offline' => array(
  6643.                     'shortopt' => 'O',
  6644.                     'doc' => 'do not attempt to download any urls or contact channels',
  6645.                     ),
  6646.                 'pretend' => array(
  6647.                     'shortopt' => 'p',
  6648.                     'doc' => 'Only list the packages that would be downloaded',
  6649.                     ),
  6650.                 ),
  6651.             'doc' => '[channel/]<package> ...
  6652. Installs one or more PEAR packages.  You can specify a package to
  6653. install in four ways:
  6654.  
  6655. "Package-1.0.tgz" : installs from a local file
  6656.  
  6657. "http://example.com/Package-1.0.tgz" : installs from
  6658. anywhere on the net.
  6659.  
  6660. "package.xml" : installs the package described in
  6661. package.xml.  Useful for testing, or for wrapping a PEAR package in
  6662. another package manager such as RPM.
  6663.  
  6664. "Package[-version/state][.tar]" : queries your default channel\'s server
  6665. ({config master_server}) and downloads the newest package with
  6666. the preferred quality/state ({config preferred_state}).
  6667.  
  6668. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  6669. Package state beta, use "Package-beta."  To retrieve an uncompressed
  6670. file, append .tar (make sure there is no file by the same name first)
  6671.  
  6672. To download a package from another channel, prefix with the channel name like
  6673. "channel/Package"
  6674.  
  6675. More than one package may be specified at once.  It is ok to mix these
  6676. four ways of specifying packages.
  6677. '),
  6678.         'upgrade' => array(
  6679.             'summary' => 'Upgrade Package',
  6680.             'function' => 'doInstall',
  6681.             'shortcut' => 'up',
  6682.             'options' => array(
  6683.                 'force' => array(
  6684.                     'shortopt' => 'f',
  6685.                     'doc' => 'overwrite newer installed packages',
  6686.                     ),
  6687.                 'loose' => array(
  6688.                     'shortopt' => 'l',
  6689.                     'doc' => 'do not check for recommended dependency version',
  6690.                     ),
  6691.                 'nodeps' => array(
  6692.                     'shortopt' => 'n',
  6693.                     'doc' => 'ignore dependencies, upgrade anyway',
  6694.                     ),
  6695.                 'register-only' => array(
  6696.                     'shortopt' => 'r',
  6697.                     'doc' => 'do not install files, only register the package as upgraded',
  6698.                     ),
  6699.                 'nobuild' => array(
  6700.                     'shortopt' => 'B',
  6701.                     'doc' => 'don\'t build C extensions',
  6702.                     ),
  6703.                 'nocompress' => array(
  6704.                     'shortopt' => 'Z',
  6705.                     'doc' => 'request uncompressed files when downloading',
  6706.                     ),
  6707.                 'installroot' => array(
  6708.                     'shortopt' => 'R',
  6709.                     'arg' => 'DIR',
  6710.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  6711.                     ),
  6712.                 'packagingroot' => array(
  6713.                     'shortopt' => 'P',
  6714.                     'arg' => 'DIR',
  6715.                     'doc' => 'root directory used when packaging files, like RPM packaging',
  6716.                     ),
  6717.                 'ignore-errors' => array(
  6718.                     'doc' => 'force install even if there were errors',
  6719.                     ),
  6720.                 'alldeps' => array(
  6721.                     'shortopt' => 'a',
  6722.                     'doc' => 'install all required and optional dependencies',
  6723.                     ),
  6724.                 'onlyreqdeps' => array(
  6725.                     'shortopt' => 'o',
  6726.                     'doc' => 'install all required dependencies',
  6727.                     ),
  6728.                 'offline' => array(
  6729.                     'shortopt' => 'O',
  6730.                     'doc' => 'do not attempt to download any urls or contact channels',
  6731.                     ),
  6732.                 'pretend' => array(
  6733.                     'shortopt' => 'p',
  6734.                     'doc' => 'Only list the packages that would be downloaded',
  6735.                     ),
  6736.                 ),
  6737.             'doc' => '<package> ...
  6738. Upgrades one or more PEAR packages.  See documentation for the
  6739. "install" command for ways to specify a package.
  6740.  
  6741. When upgrading, your package will be updated if the provided new
  6742. package has a higher version number (use the -f option if you need to
  6743. upgrade anyway).
  6744.  
  6745. More than one package may be specified at once.
  6746. '),
  6747.         'upgrade-all' => array(
  6748.             'summary' => 'Upgrade All Packages',
  6749.             'function' => 'doInstall',
  6750.             'shortcut' => 'ua',
  6751.             'options' => array(
  6752.                 'nodeps' => array(
  6753.                     'shortopt' => 'n',
  6754.                     'doc' => 'ignore dependencies, upgrade anyway',
  6755.                     ),
  6756.                 'register-only' => array(
  6757.                     'shortopt' => 'r',
  6758.                     'doc' => 'do not install files, only register the package as upgraded',
  6759.                     ),
  6760.                 'nobuild' => array(
  6761.                     'shortopt' => 'B',
  6762.                     'doc' => 'don\'t build C extensions',
  6763.                     ),
  6764.                 'nocompress' => array(
  6765.                     'shortopt' => 'Z',
  6766.                     'doc' => 'request uncompressed files when downloading',
  6767.                     ),
  6768.                 'installroot' => array(
  6769.                     'shortopt' => 'R',
  6770.                     'arg' => 'DIR',
  6771.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  6772.                     ),
  6773.                 'ignore-errors' => array(
  6774.                     'doc' => 'force install even if there were errors',
  6775.                     ),
  6776.                 'loose' => array(
  6777.                     'doc' => 'do not check for recommended dependency version',
  6778.                     ),
  6779.                 ),
  6780.             'doc' => '
  6781. Upgrades all packages that have a newer release available.  Upgrades are
  6782. done only if there is a release available of the state specified in
  6783. "preferred_state" (currently {config preferred_state}), or a state considered
  6784. more stable.
  6785. '),
  6786.         'uninstall' => array(
  6787.             'summary' => 'Un-install Package',
  6788.             'function' => 'doUninstall',
  6789.             'shortcut' => 'un',
  6790.             'options' => array(
  6791.                 'nodeps' => array(
  6792.                     'shortopt' => 'n',
  6793.                     'doc' => 'ignore dependencies, uninstall anyway',
  6794.                     ),
  6795.                 'register-only' => array(
  6796.                     'shortopt' => 'r',
  6797.                     'doc' => 'do not remove files, only register the packages as not installed',
  6798.                     ),
  6799.                 'installroot' => array(
  6800.                     'shortopt' => 'R',
  6801.                     'arg' => 'DIR',
  6802.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  6803.                     ),
  6804.                 'ignore-errors' => array(
  6805.                     'doc' => 'force install even if there were errors',
  6806.                     ),
  6807.                 'offline' => array(
  6808.                     'shortopt' => 'O',
  6809.                     'doc' => 'do not attempt to uninstall remotely',
  6810.                     ),
  6811.                 ),
  6812.             'doc' => '[channel/]<package> ...
  6813. Uninstalls one or more PEAR packages.  More than one package may be
  6814. specified at once.  Prefix with channel name to uninstall from a
  6815. channel not in your default channel ({config default_channel})
  6816. '),
  6817.         'bundle' => array(
  6818.             'summary' => 'Unpacks a Pecl Package',
  6819.             'function' => 'doBundle',
  6820.             'shortcut' => 'bun',
  6821.             'options' => array(
  6822.                 'destination' => array(
  6823.                    'shortopt' => 'd',
  6824.                     'arg' => 'DIR',
  6825.                     'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
  6826.                     ),
  6827.                 'force' => array(
  6828.                     'shortopt' => 'f',
  6829.                     'doc' => 'Force the unpacking even if there were errors in the package',
  6830.                 ),
  6831.             ),
  6832.             'doc' => '<package>
  6833. Unpacks a Pecl Package into the selected location. It will download the
  6834. package if needed.
  6835. '),
  6836.         'run-scripts' => array(
  6837.             'summary' => 'Run Post-Install Scripts bundled with a package',
  6838.             'function' => 'doRunScripts',
  6839.             'shortcut' => 'rs',
  6840.             'options' => array(
  6841.             ),
  6842.             'doc' => '<package>
  6843. Run post-installation scripts in package <package>, if any exist.
  6844. '),
  6845.     );
  6846.  
  6847.     // }}}
  6848.     // {{{ constructor
  6849.  
  6850.     /**
  6851.      * PEAR_Command_Install constructor.
  6852.      *
  6853.      * @access public
  6854.      */
  6855.     function PEAR_Command_Install(&$ui, &$config)
  6856.     {
  6857.         parent::PEAR_Command_Common($ui, $config);
  6858.     }
  6859.  
  6860.     // }}}
  6861.  
  6862.     /**
  6863.      * For unit testing purposes
  6864.      */
  6865.     function &getDownloader(&$ui, $options, &$config)
  6866.     {
  6867.         if (!class_exists('PEAR_Downloader')) {
  6868.             require_once 'phar://go-pear.phar/PEAR/Downloader.php';
  6869.         }
  6870.         $a = &new PEAR_Downloader($ui, $options, $config);
  6871.         return $a;
  6872.     }
  6873.  
  6874.     /**
  6875.      * For unit testing purposes
  6876.      */
  6877.     function &getInstaller(&$ui)
  6878.     {
  6879.         if (!class_exists('PEAR_Installer')) {
  6880.             require_once 'phar://go-pear.phar/PEAR/Installer.php';
  6881.         }
  6882.         $a = &new PEAR_Installer($ui);
  6883.         return $a;
  6884.     }
  6885.  
  6886.     function enableExtension($binaries, $type)
  6887.     {
  6888.         if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  6889.             return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  6890.         }
  6891.         $ini = $this->_parseIni($phpini);
  6892.         if (PEAR::isError($ini)) {
  6893.             return $ini;
  6894.         }
  6895.         $fp = @fopen($phpini, 'wb');
  6896.         if (!$fp) {
  6897.             return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  6898.         }
  6899.         $line = 0;
  6900.         if ($type == 'extsrc' || $type == 'extbin') {
  6901.             $search = 'extensions';
  6902.             $enable = 'extension';
  6903.         } else {
  6904.             $search = 'zend_extensions';
  6905.             ob_start();
  6906.             phpinfo(INFO_GENERAL);
  6907.             $info = ob_get_contents();
  6908.             ob_end_clean();
  6909.             $debug = function_exists('leak') ? '_debug' : '';
  6910.             $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  6911.             $enable = 'zend_extension' . $debug . $ts;
  6912.         }
  6913.         foreach ($ini[$search] as $line => $extension) {
  6914.             if (in_array($extension, $binaries, true) || in_array(
  6915.                   $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  6916.                 // already enabled - assume if one is, all are
  6917.                 return true;
  6918.             }
  6919.         }
  6920.         if ($line) {
  6921.             $newini = array_slice($ini['all'], 0, $line);
  6922.         } else {
  6923.             $newini = array();
  6924.         }
  6925.         foreach ($binaries as $binary) {
  6926.             if ($ini['extension_dir']) {
  6927.                 $binary = basename($binary);
  6928.             }
  6929.             $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
  6930.         }
  6931.         $newini = array_merge($newini, array_slice($ini['all'], $line));
  6932.         foreach ($newini as $line) {
  6933.             fwrite($fp, $line);
  6934.         }
  6935.         fclose($fp);
  6936.         return true;
  6937.     }
  6938.  
  6939.     function disableExtension($binaries, $type)
  6940.     {
  6941.         if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
  6942.             return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
  6943.         }
  6944.         $ini = $this->_parseIni($phpini);
  6945.         if (PEAR::isError($ini)) {
  6946.             return $ini;
  6947.         }
  6948.         $line = 0;
  6949.         if ($type == 'extsrc' || $type == 'extbin') {
  6950.             $search = 'extensions';
  6951.             $enable = 'extension';
  6952.         } else {
  6953.             $search = 'zend_extensions';
  6954.             ob_start();
  6955.             phpinfo(INFO_GENERAL);
  6956.             $info = ob_get_contents();
  6957.             ob_end_clean();
  6958.             $debug = function_exists('leak') ? '_debug' : '';
  6959.             $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  6960.             $enable = 'zend_extension' . $debug . $ts;
  6961.         }
  6962.         $found = false;
  6963.         foreach ($ini[$search] as $line => $extension) {
  6964.             if (in_array($extension, $binaries, true) || in_array(
  6965.                   $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
  6966.                 $found = true;
  6967.                 break;
  6968.             }
  6969.         }
  6970.         if (!$found) {
  6971.             // not enabled
  6972.             return true;
  6973.         }
  6974.         $fp = @fopen($phpini, 'wb');
  6975.         if (!$fp) {
  6976.             return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
  6977.         }
  6978.         if ($line) {
  6979.             $newini = array_slice($ini['all'], 0, $line);
  6980.             // delete the enable line
  6981.             $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
  6982.         } else {
  6983.             $newini = array_slice($ini['all'], 1);
  6984.         }
  6985.         foreach ($newini as $line) {
  6986.             fwrite($fp, $line);
  6987.         }
  6988.         fclose($fp);
  6989.         return true;
  6990.     }
  6991.  
  6992.     function _parseIni($filename)
  6993.     {
  6994.         if (file_exists($filename)) {
  6995.             if (filesize($filename) > 300000) {
  6996.                 return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
  6997.             }
  6998.             ob_start();
  6999.             phpinfo(INFO_GENERAL);
  7000.             $info = ob_get_contents();
  7001.             ob_end_clean();
  7002.             $debug = function_exists('leak') ? '_debug' : '';
  7003.             $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
  7004.             $zend_extension_line = 'zend_extension' . $debug . $ts;
  7005.             $all = @file($filename);
  7006.             if (!$all) {
  7007.                 return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
  7008.             }
  7009.             $zend_extensions = $extensions = array();
  7010.             // assume this is right, but pull from the php.ini if it is found
  7011.             $extension_dir = ini_get('extension_dir');
  7012.             foreach ($all as $linenum => $line) {
  7013.                 $line = trim($line);
  7014.                 if (!$line) {
  7015.                     continue;
  7016.                 }
  7017.                 if ($line[0] == ';') {
  7018.                     continue;
  7019.                 }
  7020.                 if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
  7021.                     $line = trim(substr($line, 13));
  7022.                     if ($line[0] == '=') {
  7023.                         $x = trim(substr($line, 1));
  7024.                         $x = explode(';', $x);
  7025.                         $extension_dir = str_replace('"', '', array_shift($x));
  7026.                         continue;
  7027.                     }
  7028.                 }
  7029.                 if (strtolower(substr($line, 0, 9)) == 'extension') {
  7030.                     $line = trim(substr($line, 9));
  7031.                     if ($line[0] == '=') {
  7032.                         $x = trim(substr($line, 1));
  7033.                         $x = explode(';', $x);
  7034.                         $extensions[$linenum] = str_replace('"', '', array_shift($x));
  7035.                         continue;
  7036.                     }
  7037.                 }
  7038.                 if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
  7039.                       $zend_extension_line) {
  7040.                     $line = trim(substr($line, strlen($zend_extension_line)));
  7041.                     if ($line[0] == '=') {
  7042.                         $x = trim(substr($line, 1));
  7043.                         $x = explode(';', $x);
  7044.                         $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
  7045.                         continue;
  7046.                     }
  7047.                 }
  7048.             }
  7049.             return array(
  7050.                 'extensions' => $extensions,
  7051.                 'zend_extensions' => $zend_extensions,
  7052.                 'extension_dir' => $extension_dir,
  7053.                 'all' => $all,
  7054.             );
  7055.         } else {
  7056.             return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
  7057.         }
  7058.     }
  7059.  
  7060.     // {{{ doInstall()
  7061.  
  7062.     function doInstall($command, $options, $params)
  7063.     {
  7064.         if (empty($this->installer)) {
  7065.             $this->installer = &$this->getInstaller($this->ui);
  7066.         }
  7067.         if ($command == 'upgrade') {
  7068.             $options['upgrade'] = true;
  7069.         }
  7070.         if (isset($options['installroot']) && isset($options['packagingroot'])) {
  7071.             return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
  7072.         }
  7073.         if (isset($options['packagingroot']) && $this->config->get('verbose') > 2) {
  7074.             $this->ui->outputData('using package root: ' . $options['packagingroot']);
  7075.         }
  7076.         $reg = &$this->config->getRegistry();
  7077.         if ($command == 'upgrade-all') {
  7078.             $options['upgrade'] = true;
  7079.             $reg = &$this->config->getRegistry();
  7080.             $savechannel = $this->config->get('default_channel');
  7081.             $params = array();
  7082.             foreach ($reg->listChannels() as $channel) {
  7083.                 if ($channel == '__uri') {
  7084.                     continue;
  7085.                 }
  7086.                 $this->config->set('default_channel', $channel);
  7087.                 $chan = &$reg->getChannel($channel);
  7088.                 if (PEAR::isError($chan)) {
  7089.                     return $this->raiseError($chan);
  7090.                 }
  7091.                 if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  7092.                       $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  7093.                     $dorest = true;
  7094.                     unset($remote);
  7095.                 } else {
  7096.                     $dorest = false;
  7097.                     $remote = &$this->config->getRemote($this->config);
  7098.                 }
  7099.                 $state = $this->config->get('preferred_state');
  7100.                 $installed = array_flip($reg->listPackages($channel));
  7101.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7102.                 if ($dorest) {
  7103.                     $rest = &$this->config->getREST('1.0', array());
  7104.                     $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
  7105.                 } else {
  7106.                     if (empty($state) || $state == 'any') {
  7107.                         $latest = $remote->call("package.listLatestReleases");
  7108.                     } else {
  7109.                         $latest = $remote->call("package.listLatestReleases", $state);
  7110.                     }
  7111.                 }
  7112.                 PEAR::staticPopErrorHandling();
  7113.                 if (PEAR::isError($latest) || !is_array($latest)) {
  7114.                     continue;
  7115.                 }
  7116.                 foreach ($latest as $package => $info) {
  7117.                     $package = strtolower($package);
  7118.                     if (!isset($installed[$package])) {
  7119.                         // skip packages we don't have installed
  7120.                         continue;
  7121.                     }
  7122.                     $inst_version = $reg->packageInfo($package, 'version', $channel);
  7123.                     if (version_compare("$info[version]", "$inst_version", "le")) {
  7124.                         // installed version is up-to-date
  7125.                         continue;
  7126.                     }
  7127.                     $params[] = $reg->parsedPackageNameToString(array('package' => $package,
  7128.                         'channel' => $channel));
  7129.                     $this->ui->outputData(array('data' => "Will upgrade $package"), $command);
  7130.                 }
  7131.             }
  7132.             $this->config->set('default_channel', $savechannel);
  7133.         }
  7134.         $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
  7135.         $errors = array();
  7136.         $downloaded = array();
  7137.         $downloaded = &$this->downloader->download($params);
  7138.         if (PEAR::isError($downloaded)) {
  7139.             return $this->raiseError($downloaded);
  7140.         }
  7141.         $errors = $this->downloader->getErrorMsgs();
  7142.         if (count($errors)) {
  7143.             foreach ($errors as $error) {
  7144.                 $err['data'][] = array($error);
  7145.             }
  7146.             $err['headline'] = 'Install Errors';
  7147.             $this->ui->outputData($err);
  7148.             if (!count($downloaded)) {
  7149.                 return $this->raiseError("$command failed");
  7150.             }
  7151.         }
  7152.         $data = array(
  7153.             'headline' => 'Packages that would be Installed'
  7154.         );
  7155.         if (isset($options['pretend'])) {
  7156.             foreach ($downloaded as $package) {
  7157.                 $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
  7158.             }
  7159.             $this->ui->outputData($data, 'pretend');
  7160.             return true;
  7161.         }
  7162.         $this->installer->setOptions($options);
  7163.         $this->installer->sortPackagesForInstall($downloaded);
  7164.         if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
  7165.             $this->raiseError($err->getMessage());
  7166.             return true;
  7167.         }
  7168.         $extrainfo = array();
  7169.         if (isset($options['packagingroot'])) {
  7170.             $packrootphp_dir = $this->installer->_prependPath(
  7171.                 $this->config->get('php_dir', null, 'pear.php.net'),
  7172.                 $options['packagingroot']);
  7173.             $instreg = new PEAR_Registry($packrootphp_dir);
  7174.         } else {
  7175.             $instreg = $reg;
  7176.         }
  7177.         foreach ($downloaded as $param) {
  7178.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7179.             $info = $this->installer->install($param, $options);
  7180.             PEAR::staticPopErrorHandling();
  7181.             if (PEAR::isError($info)) {
  7182.                 $oldinfo = $info;
  7183.                 $pkg = &$param->getPackageFile();
  7184.                 if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
  7185.                     if (!($info = $pkg->installBinary($this->installer))) {
  7186.                         $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
  7187.                         continue;
  7188.                     }
  7189.                     // we just installed a different package than requested,
  7190.                     // let's change the param and info so that the rest of this works
  7191.                     $param = $info[0];
  7192.                     $info = $info[1];
  7193.                 }
  7194.             }
  7195.             if (is_array($info)) {
  7196.                 if ($param->getPackageType() == 'extsrc' ||
  7197.                       $param->getPackageType() == 'extbin' ||
  7198.                       $param->getPackageType() == 'zendextsrc' ||
  7199.                       $param->getPackageType() == 'zendextbin') {
  7200.                     $pkg = &$param->getPackageFile();
  7201.                     if ($instbin = $pkg->getInstalledBinary()) {
  7202.                         $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
  7203.                     } else {
  7204.                         $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
  7205.                     }
  7206.                     foreach ($instpkg->getFilelist() as $name => $atts) {
  7207.                         $pinfo = pathinfo($atts['installed_as']);
  7208.                         if (!isset($pinfo['extension']) ||
  7209.                               in_array($pinfo['extension'], array('c', 'h'))) {
  7210.                             continue; // make sure we don't match php_blah.h
  7211.                         }
  7212.                         if ((strpos($pinfo['basename'], 'php_') === 0 &&
  7213.                               $pinfo['extension'] == 'dll') ||
  7214.                               // most unices
  7215.                               $pinfo['extension'] == 'so' ||
  7216.                               // hp-ux
  7217.                               $pinfo['extension'] == 'sl') {
  7218.                             $binaries[] = array($atts['installed_as'], $pinfo);
  7219.                             break;
  7220.                         }
  7221.                     }
  7222.                     foreach ($binaries as $pinfo) {
  7223.                         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7224.                         $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
  7225.                         PEAR::staticPopErrorHandling();
  7226.                         if (PEAR::isError($ret)) {
  7227.                             $extrainfo[] = $ret->getMessage();
  7228.                             if ($param->getPackageType() == 'extsrc' ||
  7229.                                   $param->getPackageType() == 'extbin') {
  7230.                                 $exttype = 'extension';
  7231.                             } else {
  7232.                                 ob_start();
  7233.                                 phpinfo(INFO_GENERAL);
  7234.                                 $info = ob_get_contents();
  7235.                                 ob_end_clean();
  7236.                                 $debug = function_exists('leak') ? '_debug' : '';
  7237.                                 $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  7238.                                 $exttype = 'zend_extension' . $debug . $ts;
  7239.                             }
  7240.                             $extrainfo[] = 'You should add "' . $exttype . '=' .
  7241.                                 $pinfo[1]['basename'] . '" to php.ini';
  7242.                         } else {
  7243.                             $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
  7244.                                 ' enabled in php.ini';
  7245.                         }
  7246.                     }
  7247.                 }
  7248.                 if ($this->config->get('verbose') > 0) {
  7249.                     $channel = $param->getChannel();
  7250.                     $label = $reg->parsedPackageNameToString(
  7251.                         array(
  7252.                             'channel' => $channel,
  7253.                             'package' => $param->getPackage(),
  7254.                             'version' => $param->getVersion(),
  7255.                         ));
  7256.                     $out = array('data' => "$command ok: $label");
  7257.                     if (isset($info['release_warnings'])) {
  7258.                         $out['release_warnings'] = $info['release_warnings'];
  7259.                     }
  7260.                     $this->ui->outputData($out, $command);
  7261.                     if (!isset($options['register-only']) && !isset($options['offline'])) {
  7262.                         if ($this->config->isDefinedLayer('ftp')) {
  7263.                             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7264.                             $info = $this->installer->ftpInstall($param);
  7265.                             PEAR::staticPopErrorHandling();
  7266.                             if (PEAR::isError($info)) {
  7267.                                 $this->ui->outputData($info->getMessage());
  7268.                                 $this->ui->outputData("remote install failed: $label");
  7269.                             } else {
  7270.                                 $this->ui->outputData("remote install ok: $label");
  7271.                             }
  7272.                         }
  7273.                     }
  7274.                 }
  7275.                 $deps = $param->getDeps();
  7276.                 if ($deps) {
  7277.                     if (isset($deps['group'])) {
  7278.                         $groups = $deps['group'];
  7279.                         if (!isset($groups[0])) {
  7280.                             $groups = array($groups);
  7281.                         }
  7282.                         foreach ($groups as $group) {
  7283.                             if ($group['attribs']['name'] == 'default') {
  7284.                                 // default group is always installed, unless the user
  7285.                                 // explicitly chooses to install another group
  7286.                                 continue;
  7287.                             }
  7288.                             $this->ui->outputData($param->getPackage() . ': Optional feature ' .
  7289.                                 $group['attribs']['name'] . ' available (' .
  7290.                                 $group['attribs']['hint'] . ')');
  7291.                         }
  7292.                         $extrainfo[] = 'To install use "pear install ' .
  7293.                             $reg->parsedPackageNameToString(
  7294.                                 array('package' => $param->getPackage(),
  7295.                                       'channel' => $param->getChannel()), true) .
  7296.                                   '#featurename"';
  7297.                     }
  7298.                 }
  7299.                 if (isset($options['installroot'])) {
  7300.                     $reg = &$this->config->getRegistry();
  7301.                 }
  7302.                 if (isset($options['packagingroot'])) {
  7303.                     $instreg = new PEAR_Registry($packrootphp_dir);
  7304.                 } else {
  7305.                     $instreg = $reg;
  7306.                 }
  7307.                 $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
  7308.                 // $pkg may be NULL if install is a 'fake' install via --packagingroot
  7309.                 if (is_object($pkg)) {
  7310.                     $pkg->setConfig($this->config);
  7311.                     if ($list = $pkg->listPostinstallScripts()) {
  7312.                         $pn = $reg->parsedPackageNameToString(array('channel' =>
  7313.                            $param->getChannel(), 'package' => $param->getPackage()), true);
  7314.                         $extrainfo[] = $pn . ' has post-install scripts:';
  7315.                         foreach ($list as $file) {
  7316.                             $extrainfo[] = $file;
  7317.                         }
  7318.                         $extrainfo[] = 'Use "pear run-scripts ' . $pn . '" to run';
  7319.                         $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
  7320.                     }
  7321.                 }
  7322.             } else {
  7323.                 return $this->raiseError("$command failed");
  7324.             }
  7325.         }
  7326.         if (count($extrainfo)) {
  7327.             foreach ($extrainfo as $info) {
  7328.                 $this->ui->outputData($info);
  7329.             }
  7330.         }
  7331.         return true;
  7332.     }
  7333.  
  7334.     // }}}
  7335.     // {{{ doUninstall()
  7336.  
  7337.     function doUninstall($command, $options, $params)
  7338.     {
  7339.         if (empty($this->installer)) {
  7340.             $this->installer = &$this->getInstaller($this->ui);
  7341.         }
  7342.         if (isset($options['remoteconfig'])) {
  7343.             $e = $this->config->readFTPConfigFile($options['remoteconfig']);
  7344.             if (!PEAR::isError($e)) {
  7345.                 $this->installer->setConfig($this->config);
  7346.             }
  7347.         }
  7348.         if (sizeof($params) < 1) {
  7349.             return $this->raiseError("Please supply the package(s) you want to uninstall");
  7350.         }
  7351.         $reg = &$this->config->getRegistry();
  7352.         $newparams = array();
  7353.         $badparams = array();
  7354.         foreach ($params as $pkg) {
  7355.             $channel = $this->config->get('default_channel');
  7356.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7357.             $parsed = $reg->parsePackageName($pkg, $channel);
  7358.             PEAR::staticPopErrorHandling();
  7359.             if (!$parsed || PEAR::isError($parsed)) {
  7360.                 $badparams[] = $pkg;
  7361.                 continue;
  7362.             }
  7363.             $package = $parsed['package'];
  7364.             $channel = $parsed['channel'];
  7365.             $info = &$reg->getPackage($package, $channel);
  7366.             if ($info === null &&
  7367.                  ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
  7368.                 // make sure this isn't a package that has flipped from pear to pecl but
  7369.                 // used a package.xml 1.0
  7370.                 $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
  7371.                 $info = &$reg->getPackage($package, $testc);
  7372.                 if ($info !== null) {
  7373.                     $channel = $testc;
  7374.                 }
  7375.             }
  7376.             if ($info === null) {
  7377.                 $badparams[] = $pkg;
  7378.             } else {
  7379.                 $newparams[] = &$info;
  7380.                 // check for binary packages (this is an alias for those packages if so)
  7381.                 if ($installedbinary = $info->getInstalledBinary()) {
  7382.                     $this->ui->log('adding binary package ' .
  7383.                         $reg->parsedPackageNameToString(array('channel' => $channel,
  7384.                             'package' => $installedbinary), true));
  7385.                     $newparams[] = &$reg->getPackage($installedbinary, $channel);
  7386.                 }
  7387.                 // add the contents of a dependency group to the list of installed packages
  7388.                 if (isset($parsed['group'])) {
  7389.                     $group = $info->getDependencyGroup($parsed['group']);
  7390.                     if ($group) {
  7391.                         $installed = &$reg->getInstalledGroup($group);
  7392.                         if ($installed) {
  7393.                             foreach ($installed as $i => $p) {
  7394.                                 $newparams[] = &$installed[$i];
  7395.                             }
  7396.                         }
  7397.                     }
  7398.                 }
  7399.             }
  7400.         }
  7401.         $err = $this->installer->sortPackagesForUninstall($newparams);
  7402.         if (PEAR::isError($err)) {
  7403.             $this->ui->outputData($err->getMessage(), $command);
  7404.             return true;
  7405.         }
  7406.         $params = $newparams;
  7407.         // twist this to use it to check on whether dependent packages are also being uninstalled
  7408.         // for circular dependencies like subpackages
  7409.         $this->installer->setUninstallPackages($newparams);
  7410.         $params = array_merge($params, $badparams);
  7411.         foreach ($params as $pkg) {
  7412.             $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  7413.             if ($err = $this->installer->uninstall($pkg, $options)) {
  7414.                 $this->installer->popErrorHandling();
  7415.                 if (PEAR::isError($err)) {
  7416.                     $this->ui->outputData($err->getMessage(), $command);
  7417.                     continue;
  7418.                 }
  7419.                 if ($pkg->getPackageType() == 'extsrc' ||
  7420.                       $pkg->getPackageType() == 'extbin' ||
  7421.                       $pkg->getPackageType() == 'zendextsrc' ||
  7422.                       $pkg->getPackageType() == 'zendextbin') {
  7423.                     if ($instbin = $pkg->getInstalledBinary()) {
  7424.                         continue; // this will be uninstalled later
  7425.                     }
  7426.                     foreach ($pkg->getFilelist() as $name => $atts) {
  7427.                         $pinfo = pathinfo($atts['installed_as']);
  7428.                         if (!isset($pinfo['extension']) ||
  7429.                               in_array($pinfo['extension'], array('c', 'h'))) {
  7430.                             continue; // make sure we don't match php_blah.h
  7431.                         }
  7432.                         if ((strpos($pinfo['basename'], 'php_') === 0 &&
  7433.                               $pinfo['extension'] == 'dll') ||
  7434.                               // most unices
  7435.                               $pinfo['extension'] == 'so' ||
  7436.                               // hp-ux
  7437.                               $pinfo['extension'] == 'sl') {
  7438.                             $binaries[] = array($atts['installed_as'], $pinfo);
  7439.                             break;
  7440.                         }
  7441.                     }
  7442.                     foreach ($binaries as $pinfo) {
  7443.                         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7444.                         $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
  7445.                         PEAR::staticPopErrorHandling();
  7446.                         if (PEAR::isError($ret)) {
  7447.                             $extrainfo[] = $ret->getMessage();
  7448.                             if ($pkg->getPackageType() == 'extsrc' ||
  7449.                                   $pkg->getPackageType() == 'extbin') {
  7450.                                 $exttype = 'extension';
  7451.                             } else {
  7452.                                 ob_start();
  7453.                                 phpinfo(INFO_GENERAL);
  7454.                                 $info = ob_get_contents();
  7455.                                 ob_end_clean();
  7456.                                 $debug = function_exists('leak') ? '_debug' : '';
  7457.                                 $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
  7458.                                 $exttype = 'zend_extension' . $debug . $ts;
  7459.                             }
  7460.                             $this->ui->outputData('Unable to remove "' . $exttype . '=' .
  7461.                                 $pinfo[1]['basename'] . '" from php.ini', $command);
  7462.                         } else {
  7463.                             $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
  7464.                                 ' disabled in php.ini', $command);
  7465.                         }
  7466.                     }
  7467.                 }
  7468.                 $savepkg = $pkg;
  7469.                 if ($this->config->get('verbose') > 0) {
  7470.                     if (is_object($pkg)) {
  7471.                         $pkg = $reg->parsedPackageNameToString($pkg);
  7472.                     }
  7473.                     $this->ui->outputData("uninstall ok: $pkg", $command);
  7474.                 }
  7475.                 if (!isset($options['offline']) && is_object($savepkg) &&
  7476.                       defined('PEAR_REMOTEINSTALL_OK')) {
  7477.                     if ($this->config->isDefinedLayer('ftp')) {
  7478.                         $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  7479.                         $info = $this->installer->ftpUninstall($savepkg);
  7480.                         $this->installer->popErrorHandling();
  7481.                         if (PEAR::isError($info)) {
  7482.                             $this->ui->outputData($info->getMessage());
  7483.                             $this->ui->outputData("remote uninstall failed: $pkg");
  7484.                         } else {
  7485.                             $this->ui->outputData("remote uninstall ok: $pkg");
  7486.                         }
  7487.                     }
  7488.                 }
  7489.             } else {
  7490.                 $this->installer->popErrorHandling();
  7491.                 if (is_object($pkg)) {
  7492.                     $pkg = $reg->parsedPackageNameToString($pkg);
  7493.                 }
  7494.                 return $this->raiseError("uninstall failed: $pkg");
  7495.             }
  7496.         }
  7497.         return true;
  7498.     }
  7499.  
  7500.     // }}}
  7501.  
  7502.  
  7503.     // }}}
  7504.     // {{{ doBundle()
  7505.     /*
  7506.     (cox) It just downloads and untars the package, does not do
  7507.             any check that the PEAR_Installer::_installFile() does.
  7508.     */
  7509.  
  7510.     function doBundle($command, $options, $params)
  7511.     {
  7512.         $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true,
  7513.             'soft' => true, 'downloadonly' => true), $this->config);
  7514.         $reg = &$this->config->getRegistry();
  7515.         if (sizeof($params) < 1) {
  7516.             return $this->raiseError("Please supply the package you want to bundle");
  7517.         }
  7518.  
  7519.         if (isset($options['destination'])) {
  7520.             if (!is_dir($options['destination'])) {
  7521.                 System::mkdir('-p ' . $options['destination']);
  7522.             }
  7523.             $dest = realpath($options['destination']);
  7524.         } else {
  7525.             $pwd = getcwd();
  7526.             if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
  7527.                 $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
  7528.             } else {
  7529.                 $dest = $pwd;
  7530.             }
  7531.         }
  7532.         $downloader->setDownloadDir($dest);
  7533.         $result = &$downloader->download(array($params[0]));
  7534.         if (PEAR::isError($result)) {
  7535.             return $result;
  7536.         }
  7537.         $pkgfile = &$result[0]->getPackageFile();
  7538.         $pkgname = $pkgfile->getName();
  7539.         $pkgversion = $pkgfile->getVersion();
  7540.  
  7541.         // Unpacking -------------------------------------------------
  7542.         $dest .= DIRECTORY_SEPARATOR . $pkgname;
  7543.         $orig = $pkgname . '-' . $pkgversion;
  7544.  
  7545.         $tar = &new Archive_Tar($pkgfile->getArchiveFile());
  7546.         if (!$tar->extractModify($dest, $orig)) {
  7547.             return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
  7548.         }
  7549.         $this->ui->outputData("Package ready at '$dest'");
  7550.     // }}}
  7551.     }
  7552.  
  7553.     // }}}
  7554.  
  7555.     function doRunScripts($command, $options, $params)
  7556.     {
  7557.         if (!isset($params[0])) {
  7558.             return $this->raiseError('run-scripts expects 1 parameter: a package name');
  7559.         }
  7560.         $reg = &$this->config->getRegistry();
  7561.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  7562.         $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  7563.         PEAR::staticPopErrorHandling();
  7564.         if (PEAR::isError($parsed)) {
  7565.             return $this->raiseError($parsed);
  7566.         }
  7567.         $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
  7568.         if (is_object($package)) {
  7569.             $package->setConfig($this->config);
  7570.             $package->runPostinstallScripts();
  7571.         } else {
  7572.             return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
  7573.         }
  7574.         $this->ui->outputData('Install scripts complete', $command);
  7575.         return true;
  7576.     }
  7577. }
  7578. ?>
  7579. <commands version="1.0">
  7580.  <install>
  7581.   <summary>Install Package</summary>
  7582.   <function>doInstall</function>
  7583.   <shortcut>i</shortcut>
  7584.   <options>
  7585.    <force>
  7586.     <shortopt>f</shortopt>
  7587.     <doc>will overwrite newer installed packages</doc>
  7588.    </force>
  7589.    <loose>
  7590.     <shortopt>l</shortopt>
  7591.     <doc>do not check for recommended dependency version</doc>
  7592.    </loose>
  7593.    <nodeps>
  7594.     <shortopt>n</shortopt>
  7595.     <doc>ignore dependencies, install anyway</doc>
  7596.    </nodeps>
  7597.    <register-only>
  7598.     <shortopt>r</shortopt>
  7599.     <doc>do not install files, only register the package as installed</doc>
  7600.    </register-only>
  7601.    <soft>
  7602.     <shortopt>s</shortopt>
  7603.     <doc>soft install, fail silently, or upgrade if already installed</doc>
  7604.    </soft>
  7605.    <nobuild>
  7606.     <shortopt>B</shortopt>
  7607.     <doc>don't build C extensions</doc>
  7608.    </nobuild>
  7609.    <nocompress>
  7610.     <shortopt>Z</shortopt>
  7611.     <doc>request uncompressed files when downloading</doc>
  7612.    </nocompress>
  7613.    <installroot>
  7614.     <shortopt>R</shortopt>
  7615.     <arg>DIR</arg>
  7616.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  7617.    </installroot>
  7618.    <ignore-errors>
  7619.     <doc>force install even if there were errors</doc>
  7620.    </ignore-errors>
  7621.    <alldeps>
  7622.     <shortopt>a</shortopt>
  7623.     <doc>install all required and optional dependencies</doc>
  7624.    </alldeps>
  7625.    <onlyreqdeps>
  7626.     <shortopt>o</shortopt>
  7627.     <doc>install all required dependencies</doc>
  7628.    </onlyreqdeps>
  7629.    <offline>
  7630.     <shortopt>O</shortopt>
  7631.     <doc>do not attempt to download any urls or contact channels</doc>
  7632.    </offline>
  7633.    <pretend>
  7634.     <shortopt>p</shortopt>
  7635.     <doc>Only list the packages that would be downloaded</doc>
  7636.    </pretend>
  7637.   </options>
  7638.   <doc>[channel/]<package> ...
  7639. Installs one or more PEAR packages.  You can specify a package to
  7640. install in four ways:
  7641.  
  7642. "Package-1.0.tgz" : installs from a local file
  7643.  
  7644. "http://example.com/Package-1.0.tgz" : installs from
  7645. anywhere on the net.
  7646.  
  7647. "package.xml" : installs the package described in
  7648. package.xml.  Useful for testing, or for wrapping a PEAR package in
  7649. another package manager such as RPM.
  7650.  
  7651. "Package[-version/state][.tar]" : queries your default channel's server
  7652. ({config master_server}) and downloads the newest package with
  7653. the preferred quality/state ({config preferred_state}).
  7654.  
  7655. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  7656. Package state beta, use "Package-beta."  To retrieve an uncompressed
  7657. file, append .tar (make sure there is no file by the same name first)
  7658.  
  7659. To download a package from another channel, prefix with the channel name like
  7660. "channel/Package"
  7661.  
  7662. More than one package may be specified at once.  It is ok to mix these
  7663. four ways of specifying packages.
  7664. </doc>
  7665.  </install>
  7666.  <upgrade>
  7667.   <summary>Upgrade Package</summary>
  7668.   <function>doInstall</function>
  7669.   <shortcut>up</shortcut>
  7670.   <options>
  7671.    <force>
  7672.     <shortopt>f</shortopt>
  7673.     <doc>overwrite newer installed packages</doc>
  7674.    </force>
  7675.    <loose>
  7676.     <shortopt>l</shortopt>
  7677.     <doc>do not check for recommended dependency version</doc>
  7678.    </loose>
  7679.    <nodeps>
  7680.     <shortopt>n</shortopt>
  7681.     <doc>ignore dependencies, upgrade anyway</doc>
  7682.    </nodeps>
  7683.    <register-only>
  7684.     <shortopt>r</shortopt>
  7685.     <doc>do not install files, only register the package as upgraded</doc>
  7686.    </register-only>
  7687.    <nobuild>
  7688.     <shortopt>B</shortopt>
  7689.     <doc>don't build C extensions</doc>
  7690.    </nobuild>
  7691.    <nocompress>
  7692.     <shortopt>Z</shortopt>
  7693.     <doc>request uncompressed files when downloading</doc>
  7694.    </nocompress>
  7695.    <installroot>
  7696.     <shortopt>R</shortopt>
  7697.     <arg>DIR</arg>
  7698.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  7699.    </installroot>
  7700.    <ignore-errors>
  7701.     <doc>force install even if there were errors</doc>
  7702.    </ignore-errors>
  7703.    <alldeps>
  7704.     <shortopt>a</shortopt>
  7705.     <doc>install all required and optional dependencies</doc>
  7706.    </alldeps>
  7707.    <onlyreqdeps>
  7708.     <shortopt>o</shortopt>
  7709.     <doc>install all required dependencies</doc>
  7710.    </onlyreqdeps>
  7711.    <offline>
  7712.     <shortopt>O</shortopt>
  7713.     <doc>do not attempt to download any urls or contact channels</doc>
  7714.    </offline>
  7715.    <pretend>
  7716.     <shortopt>p</shortopt>
  7717.     <doc>Only list the packages that would be downloaded</doc>
  7718.    </pretend>
  7719.   </options>
  7720.   <doc><package> ...
  7721. Upgrades one or more PEAR packages.  See documentation for the
  7722. "install" command for ways to specify a package.
  7723.  
  7724. When upgrading, your package will be updated if the provided new
  7725. package has a higher version number (use the -f option if you need to
  7726. upgrade anyway).
  7727.  
  7728. More than one package may be specified at once.
  7729. </doc>
  7730.  </upgrade>
  7731.  <upgrade-all>
  7732.   <summary>Upgrade All Packages</summary>
  7733.   <function>doInstall</function>
  7734.   <shortcut>ua</shortcut>
  7735.   <options>
  7736.    <nodeps>
  7737.     <shortopt>n</shortopt>
  7738.     <doc>ignore dependencies, upgrade anyway</doc>
  7739.    </nodeps>
  7740.    <register-only>
  7741.     <shortopt>r</shortopt>
  7742.     <doc>do not install files, only register the package as upgraded</doc>
  7743.    </register-only>
  7744.    <nobuild>
  7745.     <shortopt>B</shortopt>
  7746.     <doc>don't build C extensions</doc>
  7747.    </nobuild>
  7748.    <nocompress>
  7749.     <shortopt>Z</shortopt>
  7750.     <doc>request uncompressed files when downloading</doc>
  7751.    </nocompress>
  7752.    <installroot>
  7753.     <shortopt>R</shortopt>
  7754.     <arg>DIR</arg>
  7755.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  7756.    </installroot>
  7757.    <ignore-errors>
  7758.     <doc>force install even if there were errors</doc>
  7759.    </ignore-errors>
  7760.    <loose>
  7761.     <doc>do not check for recommended dependency version</doc>
  7762.    </loose>
  7763.   </options>
  7764.   <doc>
  7765. Upgrades all packages that have a newer release available.  Upgrades are
  7766. done only if there is a release available of the state specified in
  7767. "preferred_state" (currently {config preferred_state}), or a state considered
  7768. more stable.
  7769. </doc>
  7770.  </upgrade-all>
  7771.  <uninstall>
  7772.   <summary>Un-install Package</summary>
  7773.   <function>doUninstall</function>
  7774.   <shortcut>un</shortcut>
  7775.   <options>
  7776.    <nodeps>
  7777.     <shortopt>n</shortopt>
  7778.     <doc>ignore dependencies, uninstall anyway</doc>
  7779.    </nodeps>
  7780.    <register-only>
  7781.     <shortopt>r</shortopt>
  7782.     <doc>do not remove files, only register the packages as not installed</doc>
  7783.    </register-only>
  7784.    <installroot>
  7785.     <shortopt>R</shortopt>
  7786.     <arg>DIR</arg>
  7787.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  7788.    </installroot>
  7789.    <ignore-errors>
  7790.     <doc>force install even if there were errors</doc>
  7791.    </ignore-errors>
  7792.    <offline>
  7793.     <shortopt>O</shortopt>
  7794.     <doc>do not attempt to uninstall remotely</doc>
  7795.    </offline>
  7796.   </options>
  7797.   <doc>[channel/]<package> ...
  7798. Uninstalls one or more PEAR packages.  More than one package may be
  7799. specified at once.  Prefix with channel name to uninstall from a
  7800. channel not in your default channel ({config default_channel})
  7801. </doc>
  7802.  </uninstall>
  7803.  <bundle>
  7804.   <summary>Unpacks a Pecl Package</summary>
  7805.   <function>doBundle</function>
  7806.   <shortcut>bun</shortcut>
  7807.   <options>
  7808.    <destination>
  7809.     <shortopt>d</shortopt>
  7810.     <arg>DIR</arg>
  7811.     <doc>Optional destination directory for unpacking (defaults to current path or "ext" if exists)</doc>
  7812.    </destination>
  7813.    <force>
  7814.     <shortopt>f</shortopt>
  7815.     <doc>Force the unpacking even if there were errors in the package</doc>
  7816.    </force>
  7817.   </options>
  7818.   <doc><package>
  7819. Unpacks a Pecl Package into the selected location. It will download the
  7820. package if needed.
  7821. </doc>
  7822.  </bundle>
  7823.  <run-scripts>
  7824.   <summary>Run Post-Install Scripts bundled with a package</summary>
  7825.   <function>doRunScripts</function>
  7826.   <shortcut>rs</shortcut>
  7827.   <options />
  7828.   <doc><package>
  7829. Run post-installation scripts in package <package>, if any exist.
  7830. </doc>
  7831.  </run-scripts>
  7832. </commands><?php
  7833. /**
  7834.  * PEAR_Common, the base class for the PEAR Installer
  7835.  *
  7836.  * PHP versions 4 and 5
  7837.  *
  7838.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  7839.  * that is available through the world-wide-web at the following URI:
  7840.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  7841.  * the PHP License and are unable to obtain it through the web, please
  7842.  * send a note to license@php.net so we can mail you a copy immediately.
  7843.  *
  7844.  * @category   pear
  7845.  * @package    PEAR
  7846.  * @author     Stig Bakken <ssb@php.net>
  7847.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  7848.  * @author     Greg Beaver <cellog@php.net>
  7849.  * @copyright  1997-2006 The PHP Group
  7850.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  7851.  * @version    CVS: $Id: Common.php,v 1.157 2006/05/12 02:38:58 cellog Exp $
  7852.  * @link       http://pear.php.net/package/PEAR
  7853.  * @since      File available since Release 0.1.0
  7854.  * @deprecated File deprecated since Release 1.4.0a1
  7855.  */
  7856.  
  7857. /**
  7858.  * Include error handling
  7859.  */
  7860. require_once 'phar://go-pear.phar/PEAR.php';
  7861.  
  7862. // {{{ constants and globals
  7863.  
  7864. /**
  7865.  * PEAR_Common error when an invalid PHP file is passed to PEAR_Common::analyzeSourceCode()
  7866.  */
  7867. define('PEAR_COMMON_ERROR_INVALIDPHP', 1);
  7868. define('_PEAR_COMMON_PACKAGE_NAME_PREG', '[A-Za-z][a-zA-Z0-9_]+');
  7869. define('PEAR_COMMON_PACKAGE_NAME_PREG', '/^' . _PEAR_COMMON_PACKAGE_NAME_PREG . '$/');
  7870.  
  7871. // this should allow: 1, 1.0, 1.0RC1, 1.0dev, 1.0dev123234234234, 1.0a1, 1.0b1, 1.0pl1
  7872. define('_PEAR_COMMON_PACKAGE_VERSION_PREG', '\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?');
  7873. define('PEAR_COMMON_PACKAGE_VERSION_PREG', '/^' . _PEAR_COMMON_PACKAGE_VERSION_PREG . '$/i');
  7874.  
  7875. // XXX far from perfect :-)
  7876. define('_PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '(' . _PEAR_COMMON_PACKAGE_NAME_PREG .
  7877.     ')(-([.0-9a-zA-Z]+))?');
  7878. define('PEAR_COMMON_PACKAGE_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_PACKAGE_DOWNLOAD_PREG .
  7879.     '$/');
  7880.  
  7881. define('_PEAR_CHANNELS_NAME_PREG', '[A-Za-z][a-zA-Z0-9\.]+');
  7882. define('PEAR_CHANNELS_NAME_PREG', '/^' . _PEAR_CHANNELS_NAME_PREG . '$/');
  7883.  
  7884. // this should allow any dns or IP address, plus a path - NO UNDERSCORES ALLOWED
  7885. define('_PEAR_CHANNELS_SERVER_PREG', '[a-zA-Z0-9\-]+(?:\.[a-zA-Z0-9\-]+)*(\/[a-zA-Z0-9\-]+)*');
  7886. define('PEAR_CHANNELS_SERVER_PREG', '/^' . _PEAR_CHANNELS_SERVER_PREG . '$/i');
  7887.  
  7888. define('_PEAR_CHANNELS_PACKAGE_PREG',  '(' ._PEAR_CHANNELS_SERVER_PREG . ')\/('
  7889.          . _PEAR_COMMON_PACKAGE_NAME_PREG . ')');
  7890. define('PEAR_CHANNELS_PACKAGE_PREG', '/^' . _PEAR_CHANNELS_PACKAGE_PREG . '$/i');
  7891.  
  7892. define('_PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '(' . _PEAR_CHANNELS_NAME_PREG . ')::('
  7893.     . _PEAR_COMMON_PACKAGE_NAME_PREG . ')(-([.0-9a-zA-Z]+))?');
  7894. define('PEAR_COMMON_CHANNEL_DOWNLOAD_PREG', '/^' . _PEAR_COMMON_CHANNEL_DOWNLOAD_PREG . '$/');
  7895.  
  7896. /**
  7897.  * List of temporary files and directories registered by
  7898.  * PEAR_Common::addTempFile().
  7899.  * @var array
  7900.  */
  7901. $GLOBALS['_PEAR_Common_tempfiles'] = array();
  7902.  
  7903. /**
  7904.  * Valid maintainer roles
  7905.  * @var array
  7906.  */
  7907. $GLOBALS['_PEAR_Common_maintainer_roles'] = array('lead','developer','contributor','helper');
  7908.  
  7909. /**
  7910.  * Valid release states
  7911.  * @var array
  7912.  */
  7913. $GLOBALS['_PEAR_Common_release_states'] = array('alpha','beta','stable','snapshot','devel');
  7914.  
  7915. /**
  7916.  * Valid dependency types
  7917.  * @var array
  7918.  */
  7919. $GLOBALS['_PEAR_Common_dependency_types'] = array('pkg','ext','php','prog','ldlib','rtlib','os','websrv','sapi');
  7920.  
  7921. /**
  7922.  * Valid dependency relations
  7923.  * @var array
  7924.  */
  7925. $GLOBALS['_PEAR_Common_dependency_relations'] = array('has','eq','lt','le','gt','ge','not', 'ne');
  7926.  
  7927. /**
  7928.  * Valid file roles
  7929.  * @var array
  7930.  */
  7931. $GLOBALS['_PEAR_Common_file_roles'] = array('php','ext','test','doc','data','src','script');
  7932.  
  7933. /**
  7934.  * Valid replacement types
  7935.  * @var array
  7936.  */
  7937. $GLOBALS['_PEAR_Common_replacement_types'] = array('php-const', 'pear-config', 'package-info');
  7938.  
  7939. /**
  7940.  * Valid "provide" types
  7941.  * @var array
  7942.  */
  7943. $GLOBALS['_PEAR_Common_provide_types'] = array('ext', 'prog', 'class', 'function', 'feature', 'api');
  7944.  
  7945. /**
  7946.  * Valid "provide" types
  7947.  * @var array
  7948.  */
  7949. $GLOBALS['_PEAR_Common_script_phases'] = array('pre-install', 'post-install', 'pre-uninstall', 'post-uninstall', 'pre-build', 'post-build', 'pre-configure', 'post-configure', 'pre-setup', 'post-setup');
  7950.  
  7951. // }}}
  7952.  
  7953. /**
  7954.  * Class providing common functionality for PEAR administration classes.
  7955.  * @category   pear
  7956.  * @package    PEAR
  7957.  * @author     Stig Bakken <ssb@php.net>
  7958.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  7959.  * @author     Greg Beaver <cellog@php.net>
  7960.  * @copyright  1997-2006 The PHP Group
  7961.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  7962.  * @version    Release: @package_version@
  7963.  * @link       http://pear.php.net/package/PEAR
  7964.  * @since      Class available since Release 1.4.0a1
  7965.  * @deprecated This class will disappear, and its components will be spread
  7966.  *             into smaller classes, like the AT&T breakup, as of Release 1.4.0a1
  7967.  */
  7968. class PEAR_Common extends PEAR
  7969. {
  7970.     // {{{ properties
  7971.  
  7972.     /** stack of elements, gives some sort of XML context */
  7973.     var $element_stack = array();
  7974.  
  7975.     /** name of currently parsed XML element */
  7976.     var $current_element;
  7977.  
  7978.     /** array of attributes of the currently parsed XML element */
  7979.     var $current_attributes = array();
  7980.  
  7981.     /** assoc with information about a package */
  7982.     var $pkginfo = array();
  7983.  
  7984.     /**
  7985.      * User Interface object (PEAR_Frontend_* class).  If null,
  7986.      * the log() method uses print.
  7987.      * @var object
  7988.      */
  7989.     var $ui = null;
  7990.  
  7991.     /**
  7992.      * Configuration object (PEAR_Config).
  7993.      * @var object
  7994.      */
  7995.     var $config = null;
  7996.  
  7997.     var $current_path = null;
  7998.  
  7999.     /**
  8000.      * PEAR_SourceAnalyzer instance
  8001.      * @var object
  8002.      */
  8003.     var $source_analyzer = null;
  8004.     /**
  8005.      * Flag variable used to mark a valid package file
  8006.      * @var boolean
  8007.      * @access private
  8008.      */
  8009.     var $_validPackageFile;
  8010.  
  8011.     // }}}
  8012.  
  8013.     // {{{ constructor
  8014.  
  8015.     /**
  8016.      * PEAR_Common constructor
  8017.      *
  8018.      * @access public
  8019.      */
  8020.     function PEAR_Common()
  8021.     {
  8022.         parent::PEAR();
  8023.         $this->config = &PEAR_Config::singleton();
  8024.         $this->debug = $this->config->get('verbose');
  8025.     }
  8026.  
  8027.     // }}}
  8028.     // {{{ destructor
  8029.  
  8030.     /**
  8031.      * PEAR_Common destructor
  8032.      *
  8033.      * @access private
  8034.      */
  8035.     function _PEAR_Common()
  8036.     {
  8037.         // doesn't work due to bug #14744
  8038.         //$tempfiles = $this->_tempfiles;
  8039.         $tempfiles =& $GLOBALS['_PEAR_Common_tempfiles'];
  8040.         while ($file = array_shift($tempfiles)) {
  8041.             if (@is_dir($file)) {
  8042.                 if (!class_exists('System')) {
  8043.                     require_once 'phar://go-pear.phar/System.php';
  8044.                 }
  8045.                 System::rm(array('-rf', $file));
  8046.             } elseif (file_exists($file)) {
  8047.                 unlink($file);
  8048.             }
  8049.         }
  8050.     }
  8051.  
  8052.     // }}}
  8053.     // {{{ addTempFile()
  8054.  
  8055.     /**
  8056.      * Register a temporary file or directory.  When the destructor is
  8057.      * executed, all registered temporary files and directories are
  8058.      * removed.
  8059.      *
  8060.      * @param string  $file  name of file or directory
  8061.      *
  8062.      * @return void
  8063.      *
  8064.      * @access public
  8065.      */
  8066.     function addTempFile($file)
  8067.     {
  8068.         if (!class_exists('PEAR_Frontend')) {
  8069.             require_once 'phar://go-pear.phar/PEAR/Frontend.php';
  8070.         }
  8071.         PEAR_Frontend::addTempFile($file);
  8072.     }
  8073.  
  8074.     // }}}
  8075.     // {{{ mkDirHier()
  8076.  
  8077.     /**
  8078.      * Wrapper to System::mkDir(), creates a directory as well as
  8079.      * any necessary parent directories.
  8080.      *
  8081.      * @param string  $dir  directory name
  8082.      *
  8083.      * @return bool TRUE on success, or a PEAR error
  8084.      *
  8085.      * @access public
  8086.      */
  8087.     function mkDirHier($dir)
  8088.     {
  8089.         $this->log(2, "+ create dir $dir");
  8090.         if (!class_exists('System')) {
  8091.             require_once 'phar://go-pear.phar/System.php';
  8092.         }
  8093.         return System::mkDir(array('-p', $dir));
  8094.     }
  8095.  
  8096.     // }}}
  8097.     // {{{ log()
  8098.  
  8099.     /**
  8100.      * Logging method.
  8101.      *
  8102.      * @param int    $level  log level (0 is quiet, higher is noisier)
  8103.      * @param string $msg    message to write to the log
  8104.      *
  8105.      * @return void
  8106.      *
  8107.      * @access public
  8108.      * @static
  8109.      */
  8110.     function log($level, $msg, $append_crlf = true)
  8111.     {
  8112.         if ($this->debug >= $level) {
  8113.             if (!class_exists('PEAR_Frontend')) {
  8114.                 require_once 'phar://go-pear.phar/PEAR/Frontend.php';
  8115.             }
  8116.             $ui = &PEAR_Frontend::singleton();
  8117.             if (is_a($ui, 'PEAR_Frontend')) {
  8118.                 $ui->log($msg, $append_crlf);
  8119.             } else {
  8120.                 print "$msg\n";
  8121.             }
  8122.         }
  8123.     }
  8124.  
  8125.     // }}}
  8126.     // {{{ mkTempDir()
  8127.  
  8128.     /**
  8129.      * Create and register a temporary directory.
  8130.      *
  8131.      * @param string $tmpdir (optional) Directory to use as tmpdir.
  8132.      *                       Will use system defaults (for example
  8133.      *                       /tmp or c:\windows\temp) if not specified
  8134.      *
  8135.      * @return string name of created directory
  8136.      *
  8137.      * @access public
  8138.      */
  8139.     function mkTempDir($tmpdir = '')
  8140.     {
  8141.         if ($tmpdir) {
  8142.             $topt = array('-t', $tmpdir);
  8143.         } else {
  8144.             $topt = array();
  8145.         }
  8146.         $topt = array_merge($topt, array('-d', 'pear'));
  8147.         if (!class_exists('System')) {
  8148.             require_once 'phar://go-pear.phar/System.php';
  8149.         }
  8150.         if (!$tmpdir = System::mktemp($topt)) {
  8151.             return false;
  8152.         }
  8153.         $this->addTempFile($tmpdir);
  8154.         return $tmpdir;
  8155.     }
  8156.  
  8157.     // }}}
  8158.     // {{{ setFrontendObject()
  8159.  
  8160.     /**
  8161.      * Set object that represents the frontend to be used.
  8162.      *
  8163.      * @param  object Reference of the frontend object
  8164.      * @return void
  8165.      * @access public
  8166.      */
  8167.     function setFrontendObject(&$ui)
  8168.     {
  8169.         $this->ui = &$ui;
  8170.     }
  8171.  
  8172.     // }}}
  8173.  
  8174.     // {{{ infoFromTgzFile()
  8175.  
  8176.     /**
  8177.      * Returns information about a package file.  Expects the name of
  8178.      * a gzipped tar file as input.
  8179.      *
  8180.      * @param string  $file  name of .tgz file
  8181.      *
  8182.      * @return array  array with package information
  8183.      *
  8184.      * @access public
  8185.      * @deprecated use PEAR_PackageFile->fromTgzFile() instead
  8186.      *
  8187.      */
  8188.     function infoFromTgzFile($file)
  8189.     {
  8190.         $packagefile = &new PEAR_PackageFile($this->config);
  8191.         $pf = &$packagefile->fromTgzFile($file, PEAR_VALIDATE_NORMAL);
  8192.         if (PEAR::isError($pf)) {
  8193.             $errs = $pf->getUserinfo();
  8194.             if (is_array($errs)) {
  8195.                 foreach ($errs as $error) {
  8196.                     $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  8197.                 }
  8198.             }
  8199.             return $pf;
  8200.         }
  8201.         return $this->_postProcessValidPackagexml($pf);
  8202.     }
  8203.  
  8204.     // }}}
  8205.     // {{{ infoFromDescriptionFile()
  8206.  
  8207.     /**
  8208.      * Returns information about a package file.  Expects the name of
  8209.      * a package xml file as input.
  8210.      *
  8211.      * @param string  $descfile  name of package xml file
  8212.      *
  8213.      * @return array  array with package information
  8214.      *
  8215.      * @access public
  8216.      * @deprecated use PEAR_PackageFile->fromPackageFile() instead
  8217.      *
  8218.      */
  8219.     function infoFromDescriptionFile($descfile)
  8220.     {
  8221.         $packagefile = &new PEAR_PackageFile($this->config);
  8222.         $pf = &$packagefile->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
  8223.         if (PEAR::isError($pf)) {
  8224.             $errs = $pf->getUserinfo();
  8225.             if (is_array($errs)) {
  8226.                 foreach ($errs as $error) {
  8227.                     $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  8228.                 }
  8229.             }
  8230.             return $pf;
  8231.         }
  8232.         return $this->_postProcessValidPackagexml($pf);
  8233.     }
  8234.  
  8235.     // }}}
  8236.     // {{{ infoFromString()
  8237.  
  8238.     /**
  8239.      * Returns information about a package file.  Expects the contents
  8240.      * of a package xml file as input.
  8241.      *
  8242.      * @param string  $data  contents of package.xml file
  8243.      *
  8244.      * @return array   array with package information
  8245.      *
  8246.      * @access public
  8247.      * @deprecated use PEAR_PackageFile->fromXmlstring() instead
  8248.      *
  8249.      */
  8250.     function infoFromString($data)
  8251.     {
  8252.         $packagefile = &new PEAR_PackageFile($this->config);
  8253.         $pf = &$packagefile->fromXmlString($data, PEAR_VALIDATE_NORMAL, false);
  8254.         if (PEAR::isError($pf)) {
  8255.             $errs = $pf->getUserinfo();
  8256.             if (is_array($errs)) {
  8257.                 foreach ($errs as $error) {
  8258.                     $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  8259.                 }
  8260.             }
  8261.             return $pf;
  8262.         }
  8263.         return $this->_postProcessValidPackagexml($pf);
  8264.     }
  8265.     // }}}
  8266.  
  8267.     /**
  8268.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  8269.      * @return array
  8270.      */
  8271.     function _postProcessValidPackagexml(&$pf)
  8272.     {
  8273.         if (is_a($pf, 'PEAR_PackageFile_v2')) {
  8274.             // sort of make this into a package.xml 1.0-style array
  8275.             // changelog is not converted to old format.
  8276.             $arr = $pf->toArray(true);
  8277.             $arr = array_merge($arr, $arr['old']);
  8278.             unset($arr['old']);
  8279.             unset($arr['xsdversion']);
  8280.             unset($arr['contents']);
  8281.             unset($arr['compatible']);
  8282.             unset($arr['channel']);
  8283.             unset($arr['uri']);
  8284.             unset($arr['dependencies']);
  8285.             unset($arr['phprelease']);
  8286.             unset($arr['extsrcrelease']);
  8287.             unset($arr['zendextsrcrelease']);
  8288.             unset($arr['extbinrelease']);
  8289.             unset($arr['zendextbinrelease']);
  8290.             unset($arr['bundle']);
  8291.             unset($arr['lead']);
  8292.             unset($arr['developer']);
  8293.             unset($arr['helper']);
  8294.             unset($arr['contributor']);
  8295.             $arr['filelist'] = $pf->getFilelist();
  8296.             $this->pkginfo = $arr;
  8297.             return $arr;
  8298.         } else {
  8299.             $this->pkginfo = $pf->toArray();
  8300.             return $this->pkginfo;
  8301.         }
  8302.     }
  8303.     // {{{ infoFromAny()
  8304.  
  8305.     /**
  8306.      * Returns package information from different sources
  8307.      *
  8308.      * This method is able to extract information about a package
  8309.      * from a .tgz archive or from a XML package definition file.
  8310.      *
  8311.      * @access public
  8312.      * @param  string Filename of the source ('package.xml', '<package>.tgz')
  8313.      * @return string
  8314.      * @deprecated use PEAR_PackageFile->fromAnyFile() instead
  8315.      */
  8316.     function infoFromAny($info)
  8317.     {
  8318.         if (is_string($info) && file_exists($info)) {
  8319.             $packagefile = &new PEAR_PackageFile($this->config);
  8320.             $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
  8321.             if (PEAR::isError($pf)) {
  8322.                 $errs = $pf->getUserinfo();
  8323.                 if (is_array($errs)) {
  8324.                     foreach ($errs as $error) {
  8325.                         $e = $this->raiseError($error['message'], $error['code'], null, null, $error);
  8326.                     }
  8327.                 }
  8328.                 return $pf;
  8329.             }
  8330.             return $this->_postProcessValidPackagexml($pf);
  8331.         }
  8332.         return $info;
  8333.     }
  8334.  
  8335.     // }}}
  8336.     // {{{ xmlFromInfo()
  8337.  
  8338.     /**
  8339.      * Return an XML document based on the package info (as returned
  8340.      * by the PEAR_Common::infoFrom* methods).
  8341.      *
  8342.      * @param array  $pkginfo  package info
  8343.      *
  8344.      * @return string XML data
  8345.      *
  8346.      * @access public
  8347.      * @deprecated use a PEAR_PackageFile_v* object's generator instead
  8348.      */
  8349.     function xmlFromInfo($pkginfo)
  8350.     {
  8351.         $config = &PEAR_Config::singleton();
  8352.         $packagefile = &new PEAR_PackageFile($config);
  8353.         $pf = &$packagefile->fromArray($pkginfo);
  8354.         $gen = &$pf->getDefaultGenerator();
  8355.         return $gen->toXml(PEAR_VALIDATE_PACKAGING);
  8356.     }
  8357.  
  8358.     // }}}
  8359.     // {{{ validatePackageInfo()
  8360.  
  8361.     /**
  8362.      * Validate XML package definition file.
  8363.      *
  8364.      * @param  string $info Filename of the package archive or of the
  8365.      *                package definition file
  8366.      * @param  array $errors Array that will contain the errors
  8367.      * @param  array $warnings Array that will contain the warnings
  8368.      * @param  string $dir_prefix (optional) directory where source files
  8369.      *                may be found, or empty if they are not available
  8370.      * @access public
  8371.      * @return boolean
  8372.      * @deprecated use the validation of PEAR_PackageFile objects
  8373.      */
  8374.     function validatePackageInfo($info, &$errors, &$warnings, $dir_prefix = '')
  8375.     {
  8376.         $config = &PEAR_Config::singleton();
  8377.         $packagefile = &new PEAR_PackageFile($config);
  8378.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  8379.         if (strpos($info, '<?xml') !== false) {
  8380.             $pf = &$packagefile->fromXmlString($info, PEAR_VALIDATE_NORMAL, '');
  8381.         } else {
  8382.             $pf = &$packagefile->fromAnyFile($info, PEAR_VALIDATE_NORMAL);
  8383.         }
  8384.         PEAR::staticPopErrorHandling();
  8385.         if (PEAR::isError($pf)) {
  8386.             $errs = $pf->getUserinfo();
  8387.             if (is_array($errs)) {
  8388.                 foreach ($errs as $error) {
  8389.                     if ($error['level'] == 'error') {
  8390.                         $errors[] = $error['message'];
  8391.                     } else {
  8392.                         $warnings[] = $error['message'];
  8393.                     }
  8394.                 }
  8395.             }
  8396.             return false;
  8397.         }
  8398.         return true;
  8399.     }
  8400.  
  8401.     // }}}
  8402.     // {{{ buildProvidesArray()
  8403.  
  8404.     /**
  8405.      * Build a "provides" array from data returned by
  8406.      * analyzeSourceCode().  The format of the built array is like
  8407.      * this:
  8408.      *
  8409.      *  array(
  8410.      *    'class;MyClass' => 'array('type' => 'class', 'name' => 'MyClass'),
  8411.      *    ...
  8412.      *  )
  8413.      *
  8414.      *
  8415.      * @param array $srcinfo array with information about a source file
  8416.      * as returned by the analyzeSourceCode() method.
  8417.      *
  8418.      * @return void
  8419.      *
  8420.      * @access public
  8421.      *
  8422.      */
  8423.     function buildProvidesArray($srcinfo)
  8424.     {
  8425.         $file = basename($srcinfo['source_file']);
  8426.         $pn = '';
  8427.         if (isset($this->_packageName)) {
  8428.             $pn = $this->_packageName;
  8429.         }
  8430.         $pnl = strlen($pn);
  8431.         foreach ($srcinfo['declared_classes'] as $class) {
  8432.             $key = "class;$class";
  8433.             if (isset($this->pkginfo['provides'][$key])) {
  8434.                 continue;
  8435.             }
  8436.             $this->pkginfo['provides'][$key] =
  8437.                 array('file'=> $file, 'type' => 'class', 'name' => $class);
  8438.             if (isset($srcinfo['inheritance'][$class])) {
  8439.                 $this->pkginfo['provides'][$key]['extends'] =
  8440.                     $srcinfo['inheritance'][$class];
  8441.             }
  8442.         }
  8443.         foreach ($srcinfo['declared_methods'] as $class => $methods) {
  8444.             foreach ($methods as $method) {
  8445.                 $function = "$class::$method";
  8446.                 $key = "function;$function";
  8447.                 if ($method{0} == '_' || !strcasecmp($method, $class) ||
  8448.                     isset($this->pkginfo['provides'][$key])) {
  8449.                     continue;
  8450.                 }
  8451.                 $this->pkginfo['provides'][$key] =
  8452.                     array('file'=> $file, 'type' => 'function', 'name' => $function);
  8453.             }
  8454.         }
  8455.  
  8456.         foreach ($srcinfo['declared_functions'] as $function) {
  8457.             $key = "function;$function";
  8458.             if ($function{0} == '_' || isset($this->pkginfo['provides'][$key])) {
  8459.                 continue;
  8460.             }
  8461.             if (!strstr($function, '::') && strncasecmp($function, $pn, $pnl)) {
  8462.                 $warnings[] = "in1 " . $file . ": function \"$function\" not prefixed with package name \"$pn\"";
  8463.             }
  8464.             $this->pkginfo['provides'][$key] =
  8465.                 array('file'=> $file, 'type' => 'function', 'name' => $function);
  8466.         }
  8467.     }
  8468.  
  8469.     // }}}
  8470.     // {{{ analyzeSourceCode()
  8471.  
  8472.     /**
  8473.      * Analyze the source code of the given PHP file
  8474.      *
  8475.      * @param  string Filename of the PHP file
  8476.      * @return mixed
  8477.      * @access public
  8478.      */
  8479.     function analyzeSourceCode($file)
  8480.     {
  8481.         if (!function_exists("token_get_all")) {
  8482.             return false;
  8483.         }
  8484.         if (!defined('T_DOC_COMMENT')) {
  8485.             define('T_DOC_COMMENT', T_COMMENT);
  8486.         }
  8487.         if (!defined('T_INTERFACE')) {
  8488.             define('T_INTERFACE', -1);
  8489.         }
  8490.         if (!defined('T_IMPLEMENTS')) {
  8491.             define('T_IMPLEMENTS', -1);
  8492.         }
  8493.         if (!$fp = @fopen($file, "r")) {
  8494.             return false;
  8495.         }
  8496.         fclose($fp);
  8497.         $contents = file_get_contents($file);
  8498.         $tokens = token_get_all($contents);
  8499. /*
  8500.         for ($i = 0; $i < sizeof($tokens); $i++) {
  8501.             @list($token, $data) = $tokens[$i];
  8502.             if (is_string($token)) {
  8503.                 var_dump($token);
  8504.             } else {
  8505.                 print token_name($token) . ' ';
  8506.                 var_dump(rtrim($data));
  8507.             }
  8508.         }
  8509. */
  8510.         $look_for = 0;
  8511.         $paren_level = 0;
  8512.         $bracket_level = 0;
  8513.         $brace_level = 0;
  8514.         $lastphpdoc = '';
  8515.         $current_class = '';
  8516.         $current_interface = '';
  8517.         $current_class_level = -1;
  8518.         $current_function = '';
  8519.         $current_function_level = -1;
  8520.         $declared_classes = array();
  8521.         $declared_interfaces = array();
  8522.         $declared_functions = array();
  8523.         $declared_methods = array();
  8524.         $used_classes = array();
  8525.         $used_functions = array();
  8526.         $extends = array();
  8527.         $implements = array();
  8528.         $nodeps = array();
  8529.         $inquote = false;
  8530.         $interface = false;
  8531.         for ($i = 0; $i < sizeof($tokens); $i++) {
  8532.             if (is_array($tokens[$i])) {
  8533.                 list($token, $data) = $tokens[$i];
  8534.             } else {
  8535.                 $token = $tokens[$i];
  8536.                 $data = '';
  8537.             }
  8538.             if ($inquote) {
  8539.                 if ($token != '"') {
  8540.                     continue;
  8541.                 } else {
  8542.                     $inquote = false;
  8543.                     continue;
  8544.                 }
  8545.             }
  8546.             switch ($token) {
  8547.                 case T_WHITESPACE:
  8548.                     continue;
  8549.                 case ';':
  8550.                     if ($interface) {
  8551.                         $current_function = '';
  8552.                         $current_function_level = -1;
  8553.                     }
  8554.                     break;
  8555.                 case '"':
  8556.                     $inquote = true;
  8557.                     break;
  8558.                 case T_CURLY_OPEN:
  8559.                 case T_DOLLAR_OPEN_CURLY_BRACES:
  8560.                 case '{': $brace_level++; continue 2;
  8561.                 case '}':
  8562.                     $brace_level--;
  8563.                     if ($current_class_level == $brace_level) {
  8564.                         $current_class = '';
  8565.                         $current_class_level = -1;
  8566.                     }
  8567.                     if ($current_function_level == $brace_level) {
  8568.                         $current_function = '';
  8569.                         $current_function_level = -1;
  8570.                     }
  8571.                     continue 2;
  8572.                 case '[': $bracket_level++; continue 2;
  8573.                 case ']': $bracket_level--; continue 2;
  8574.                 case '(': $paren_level++;   continue 2;
  8575.                 case ')': $paren_level--;   continue 2;
  8576.                 case T_INTERFACE:
  8577.                     $interface = true;
  8578.                 case T_CLASS:
  8579.                     if (($current_class_level != -1) || ($current_function_level != -1)) {
  8580.                         PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
  8581.                             PEAR_COMMON_ERROR_INVALIDPHP);
  8582.                         return false;
  8583.                     }
  8584.                 case T_FUNCTION:
  8585.                 case T_NEW:
  8586.                 case T_EXTENDS:
  8587.                 case T_IMPLEMENTS:
  8588.                     $look_for = $token;
  8589.                     continue 2;
  8590.                 case T_STRING:
  8591.                     if (version_compare(zend_version(), '2.0', '<')) {
  8592.                         if (in_array(strtolower($data),
  8593.                             array('public', 'private', 'protected', 'abstract',
  8594.                                   'interface', 'implements', 'throw') 
  8595.                                  )) {
  8596.                             PEAR::raiseError('Error: PHP5 token encountered in ' . $file . 
  8597.                             'packaging should be done in PHP 5');
  8598.                             return false;
  8599.                         }
  8600.                     }
  8601.                     if ($look_for == T_CLASS) {
  8602.                         $current_class = $data;
  8603.                         $current_class_level = $brace_level;
  8604.                         $declared_classes[] = $current_class;
  8605.                     } elseif ($look_for == T_INTERFACE) {
  8606.                         $current_interface = $data;
  8607.                         $current_class_level = $brace_level;
  8608.                         $declared_interfaces[] = $current_interface;
  8609.                     } elseif ($look_for == T_IMPLEMENTS) {
  8610.                         $implements[$current_class] = $data;
  8611.                     } elseif ($look_for == T_EXTENDS) {
  8612.                         $extends[$current_class] = $data;
  8613.                     } elseif ($look_for == T_FUNCTION) {
  8614.                         if ($current_class) {
  8615.                             $current_function = "$current_class::$data";
  8616.                             $declared_methods[$current_class][] = $data;
  8617.                         } elseif ($current_interface) {
  8618.                             $current_function = "$current_interface::$data";
  8619.                             $declared_methods[$current_interface][] = $data;
  8620.                         } else {
  8621.                             $current_function = $data;
  8622.                             $declared_functions[] = $current_function;
  8623.                         }
  8624.                         $current_function_level = $brace_level;
  8625.                         $m = array();
  8626.                     } elseif ($look_for == T_NEW) {
  8627.                         $used_classes[$data] = true;
  8628.                     }
  8629.                     $look_for = 0;
  8630.                     continue 2;
  8631.                 case T_VARIABLE:
  8632.                     $look_for = 0;
  8633.                     continue 2;
  8634.                 case T_DOC_COMMENT:
  8635.                 case T_COMMENT:
  8636.                     if (preg_match('!^/\*\*\s!', $data)) {
  8637.                         $lastphpdoc = $data;
  8638.                         if (preg_match_all('/@nodep\s+(\S+)/', $lastphpdoc, $m)) {
  8639.                             $nodeps = array_merge($nodeps, $m[1]);
  8640.                         }
  8641.                     }
  8642.                     continue 2;
  8643.                 case T_DOUBLE_COLON:
  8644.                     if (!($tokens[$i - 1][0] == T_WHITESPACE || $tokens[$i - 1][0] == T_STRING)) {
  8645.                         PEAR::raiseError("Parser error: invalid PHP found in file \"$file\"",
  8646.                             PEAR_COMMON_ERROR_INVALIDPHP);
  8647.                         return false;
  8648.                     }
  8649.                     $class = $tokens[$i - 1][1];
  8650.                     if (strtolower($class) != 'parent') {
  8651.                         $used_classes[$class] = true;
  8652.                     }
  8653.                     continue 2;
  8654.             }
  8655.         }
  8656.         return array(
  8657.             "source_file" => $file,
  8658.             "declared_classes" => $declared_classes,
  8659.             "declared_interfaces" => $declared_interfaces,
  8660.             "declared_methods" => $declared_methods,
  8661.             "declared_functions" => $declared_functions,
  8662.             "used_classes" => array_diff(array_keys($used_classes), $nodeps),
  8663.             "inheritance" => $extends,
  8664.             "implements" => $implements,
  8665.             );
  8666.     }
  8667.  
  8668.     // }}}
  8669.     // {{{  betterStates()
  8670.  
  8671.     /**
  8672.      * Return an array containing all of the states that are more stable than
  8673.      * or equal to the passed in state
  8674.      *
  8675.      * @param string Release state
  8676.      * @param boolean Determines whether to include $state in the list
  8677.      * @return false|array False if $state is not a valid release state
  8678.      */
  8679.     function betterStates($state, $include = false)
  8680.     {
  8681.         static $states = array('snapshot', 'devel', 'alpha', 'beta', 'stable');
  8682.         $i = array_search($state, $states);
  8683.         if ($i === false) {
  8684.             return false;
  8685.         }
  8686.         if ($include) {
  8687.             $i--;
  8688.         }
  8689.         return array_slice($states, $i + 1);
  8690.     }
  8691.  
  8692.     // }}}
  8693.     // {{{ detectDependencies()
  8694.  
  8695.     function detectDependencies($any, $status_callback = null)
  8696.     {
  8697.         if (!function_exists("token_get_all")) {
  8698.             return false;
  8699.         }
  8700.         if (PEAR::isError($info = $this->infoFromAny($any))) {
  8701.             return $this->raiseError($info);
  8702.         }
  8703.         if (!is_array($info)) {
  8704.             return false;
  8705.         }
  8706.         $deps = array();
  8707.         $used_c = $decl_c = $decl_f = $decl_m = array();
  8708.         foreach ($info['filelist'] as $file => $fa) {
  8709.             $tmp = $this->analyzeSourceCode($file);
  8710.             $used_c = @array_merge($used_c, $tmp['used_classes']);
  8711.             $decl_c = @array_merge($decl_c, $tmp['declared_classes']);
  8712.             $decl_f = @array_merge($decl_f, $tmp['declared_functions']);
  8713.             $decl_m = @array_merge($decl_m, $tmp['declared_methods']);
  8714.             $inheri = @array_merge($inheri, $tmp['inheritance']);
  8715.         }
  8716.         $used_c = array_unique($used_c);
  8717.         $decl_c = array_unique($decl_c);
  8718.         $undecl_c = array_diff($used_c, $decl_c);
  8719.         return array('used_classes' => $used_c,
  8720.                      'declared_classes' => $decl_c,
  8721.                      'declared_methods' => $decl_m,
  8722.                      'declared_functions' => $decl_f,
  8723.                      'undeclared_classes' => $undecl_c,
  8724.                      'inheritance' => $inheri,
  8725.                      );
  8726.     }
  8727.  
  8728.     // }}}
  8729.     // {{{ getUserRoles()
  8730.  
  8731.     /**
  8732.      * Get the valid roles for a PEAR package maintainer
  8733.      *
  8734.      * @return array
  8735.      * @static
  8736.      */
  8737.     function getUserRoles()
  8738.     {
  8739.         return $GLOBALS['_PEAR_Common_maintainer_roles'];
  8740.     }
  8741.  
  8742.     // }}}
  8743.     // {{{ getReleaseStates()
  8744.  
  8745.     /**
  8746.      * Get the valid package release states of packages
  8747.      *
  8748.      * @return array
  8749.      * @static
  8750.      */
  8751.     function getReleaseStates()
  8752.     {
  8753.         return $GLOBALS['_PEAR_Common_release_states'];
  8754.     }
  8755.  
  8756.     // }}}
  8757.     // {{{ getDependencyTypes()
  8758.  
  8759.     /**
  8760.      * Get the implemented dependency types (php, ext, pkg etc.)
  8761.      *
  8762.      * @return array
  8763.      * @static
  8764.      */
  8765.     function getDependencyTypes()
  8766.     {
  8767.         return $GLOBALS['_PEAR_Common_dependency_types'];
  8768.     }
  8769.  
  8770.     // }}}
  8771.     // {{{ getDependencyRelations()
  8772.  
  8773.     /**
  8774.      * Get the implemented dependency relations (has, lt, ge etc.)
  8775.      *
  8776.      * @return array
  8777.      * @static
  8778.      */
  8779.     function getDependencyRelations()
  8780.     {
  8781.         return $GLOBALS['_PEAR_Common_dependency_relations'];
  8782.     }
  8783.  
  8784.     // }}}
  8785.     // {{{ getFileRoles()
  8786.  
  8787.     /**
  8788.      * Get the implemented file roles
  8789.      *
  8790.      * @return array
  8791.      * @static
  8792.      */
  8793.     function getFileRoles()
  8794.     {
  8795.         return $GLOBALS['_PEAR_Common_file_roles'];
  8796.     }
  8797.  
  8798.     // }}}
  8799.     // {{{ getReplacementTypes()
  8800.  
  8801.     /**
  8802.      * Get the implemented file replacement types in
  8803.      *
  8804.      * @return array
  8805.      * @static
  8806.      */
  8807.     function getReplacementTypes()
  8808.     {
  8809.         return $GLOBALS['_PEAR_Common_replacement_types'];
  8810.     }
  8811.  
  8812.     // }}}
  8813.     // {{{ getProvideTypes()
  8814.  
  8815.     /**
  8816.      * Get the implemented file replacement types in
  8817.      *
  8818.      * @return array
  8819.      * @static
  8820.      */
  8821.     function getProvideTypes()
  8822.     {
  8823.         return $GLOBALS['_PEAR_Common_provide_types'];
  8824.     }
  8825.  
  8826.     // }}}
  8827.     // {{{ getScriptPhases()
  8828.  
  8829.     /**
  8830.      * Get the implemented file replacement types in
  8831.      *
  8832.      * @return array
  8833.      * @static
  8834.      */
  8835.     function getScriptPhases()
  8836.     {
  8837.         return $GLOBALS['_PEAR_Common_script_phases'];
  8838.     }
  8839.  
  8840.     // }}}
  8841.     // {{{ validPackageName()
  8842.  
  8843.     /**
  8844.      * Test whether a string contains a valid package name.
  8845.      *
  8846.      * @param string $name the package name to test
  8847.      *
  8848.      * @return bool
  8849.      *
  8850.      * @access public
  8851.      */
  8852.     function validPackageName($name)
  8853.     {
  8854.         return (bool)preg_match(PEAR_COMMON_PACKAGE_NAME_PREG, $name);
  8855.     }
  8856.  
  8857.  
  8858.     // }}}
  8859.     // {{{ validPackageVersion()
  8860.  
  8861.     /**
  8862.      * Test whether a string contains a valid package version.
  8863.      *
  8864.      * @param string $ver the package version to test
  8865.      *
  8866.      * @return bool
  8867.      *
  8868.      * @access public
  8869.      */
  8870.     function validPackageVersion($ver)
  8871.     {
  8872.         return (bool)preg_match(PEAR_COMMON_PACKAGE_VERSION_PREG, $ver);
  8873.     }
  8874.  
  8875.  
  8876.     // }}}
  8877.  
  8878.     // {{{ downloadHttp()
  8879.  
  8880.     /**
  8881.      * Download a file through HTTP.  Considers suggested file name in
  8882.      * Content-disposition: header and can run a callback function for
  8883.      * different events.  The callback will be called with two
  8884.      * parameters: the callback type, and parameters.  The implemented
  8885.      * callback types are:
  8886.      *
  8887.      *  'setup'       called at the very beginning, parameter is a UI object
  8888.      *                that should be used for all output
  8889.      *  'message'     the parameter is a string with an informational message
  8890.      *  'saveas'      may be used to save with a different file name, the
  8891.      *                parameter is the filename that is about to be used.
  8892.      *                If a 'saveas' callback returns a non-empty string,
  8893.      *                that file name will be used as the filename instead.
  8894.      *                Note that $save_dir will not be affected by this, only
  8895.      *                the basename of the file.
  8896.      *  'start'       download is starting, parameter is number of bytes
  8897.      *                that are expected, or -1 if unknown
  8898.      *  'bytesread'   parameter is the number of bytes read so far
  8899.      *  'done'        download is complete, parameter is the total number
  8900.      *                of bytes read
  8901.      *  'connfailed'  if the TCP connection fails, this callback is called
  8902.      *                with array(host,port,errno,errmsg)
  8903.      *  'writefailed' if writing to disk fails, this callback is called
  8904.      *                with array(destfile,errmsg)
  8905.      *
  8906.      * If an HTTP proxy has been configured (http_proxy PEAR_Config
  8907.      * setting), the proxy will be used.
  8908.      *
  8909.      * @param string  $url       the URL to download
  8910.      * @param object  $ui        PEAR_Frontend_* instance
  8911.      * @param object  $config    PEAR_Config instance
  8912.      * @param string  $save_dir  (optional) directory to save file in
  8913.      * @param mixed   $callback  (optional) function/method to call for status
  8914.      *                           updates
  8915.      *
  8916.      * @return string  Returns the full path of the downloaded file or a PEAR
  8917.      *                 error on failure.  If the error is caused by
  8918.      *                 socket-related errors, the error object will
  8919.      *                 have the fsockopen error code available through
  8920.      *                 getCode().
  8921.      *
  8922.      * @access public
  8923.      * @deprecated in favor of PEAR_Downloader::downloadHttp()
  8924.      */
  8925.     function downloadHttp($url, &$ui, $save_dir = '.', $callback = null)
  8926.     {
  8927.         if (!class_exists('PEAR_Downloader')) {
  8928.             require_once 'phar://go-pear.phar/PEAR/Downloader.php';
  8929.         }
  8930.         return PEAR_Downloader::downloadHttp($url, $ui, $save_dir, $callback);
  8931.     }
  8932.  
  8933.     // }}}
  8934.  
  8935.     /**
  8936.      * @param string $path relative or absolute include path
  8937.      * @return boolean
  8938.      * @static
  8939.      */
  8940.     function isIncludeable($path)
  8941.     {
  8942.         if (file_exists($path) && is_readable($path)) {
  8943.             return true;
  8944.         }
  8945.         $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
  8946.         foreach ($ipath as $include) {
  8947.             $test = realpath($include . DIRECTORY_SEPARATOR . $path);
  8948.             if (file_exists($test) && is_readable($test)) {
  8949.                 return true;
  8950.             }
  8951.         }
  8952.         return false;
  8953.     }
  8954. }
  8955. require_once 'phar://go-pear.phar/PEAR/Config.php';
  8956. require_once 'phar://go-pear.phar/PEAR/PackageFile.php';
  8957. ?><?php
  8958. /**
  8959.  * PEAR_Config, customized configuration handling for the PEAR Installer
  8960.  *
  8961.  * PHP versions 4 and 5
  8962.  *
  8963.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  8964.  * that is available through the world-wide-web at the following URI:
  8965.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  8966.  * the PHP License and are unable to obtain it through the web, please
  8967.  * send a note to license@php.net so we can mail you a copy immediately.
  8968.  *
  8969.  * @category   pear
  8970.  * @package    PEAR
  8971.  * @author     Stig Bakken <ssb@php.net>
  8972.  * @author     Greg Beaver <cellog@php.net>
  8973.  * @copyright  1997-2006 The PHP Group
  8974.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  8975.  * @version    CVS: $Id: Config.php,v 1.135 2006/09/24 05:45:26 cellog Exp $
  8976.  * @link       http://pear.php.net/package/PEAR
  8977.  * @since      File available since Release 0.1
  8978.  */
  8979.  
  8980. /**
  8981.  * Required for error handling
  8982.  */
  8983. require_once 'phar://go-pear.phar/PEAR.php';
  8984. require_once 'phar://go-pear.phar/PEAR/Registry.php';
  8985. require_once 'phar://go-pear.phar/PEAR/Installer/Role.php';
  8986. require_once 'phar://go-pear.phar/System.php';
  8987. require_once 'phar://go-pear.phar/PEAR/Remote.php';
  8988.  
  8989. /**
  8990.  * Last created PEAR_Config instance.
  8991.  * @var object
  8992.  */
  8993. $GLOBALS['_PEAR_Config_instance'] = null;
  8994. if (!defined('PEAR_INSTALL_DIR') || !PEAR_INSTALL_DIR) {
  8995.     $PEAR_INSTALL_DIR = PHP_LIBDIR . DIRECTORY_SEPARATOR . 'pear';
  8996. } else {
  8997.     $PEAR_INSTALL_DIR = PEAR_INSTALL_DIR;
  8998. }
  8999.  
  9000. // Below we define constants with default values for all configuration
  9001. // parameters except username/password.  All of them can have their
  9002. // defaults set through environment variables.  The reason we use the
  9003. // PHP_ prefix is for some security, PHP protects environment
  9004. // variables starting with PHP_*.
  9005.  
  9006. // default channel and preferred mirror is based on whether we are invoked through
  9007. // the "pear" or the "pecl" command
  9008.  
  9009. if (!defined('PEAR_RUNTYPE') || PEAR_RUNTYPE == 'pear') {
  9010.     define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pear.php.net');
  9011. } else {
  9012.     define('PEAR_CONFIG_DEFAULT_CHANNEL', 'pecl.php.net');
  9013. }
  9014.  
  9015. if (getenv('PHP_PEAR_SYSCONF_DIR')) {
  9016.     define('PEAR_CONFIG_SYSCONFDIR', getenv('PHP_PEAR_SYSCONF_DIR'));
  9017. } elseif (getenv('SystemRoot')) {
  9018.     define('PEAR_CONFIG_SYSCONFDIR', getenv('SystemRoot'));
  9019. } else {
  9020.     define('PEAR_CONFIG_SYSCONFDIR', PHP_SYSCONFDIR);
  9021. }
  9022.  
  9023. // Default for master_server
  9024. if (getenv('PHP_PEAR_MASTER_SERVER')) {
  9025.     define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', getenv('PHP_PEAR_MASTER_SERVER'));
  9026. } else {
  9027.     define('PEAR_CONFIG_DEFAULT_MASTER_SERVER', 'pear.php.net');
  9028. }
  9029.  
  9030. // Default for http_proxy
  9031. if (getenv('PHP_PEAR_HTTP_PROXY')) {
  9032.     define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('PHP_PEAR_HTTP_PROXY'));
  9033. } elseif (getenv('http_proxy')) {
  9034.     define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', getenv('http_proxy'));
  9035. } else {
  9036.     define('PEAR_CONFIG_DEFAULT_HTTP_PROXY', '');
  9037. }
  9038.  
  9039. // Default for php_dir
  9040. if (getenv('PHP_PEAR_INSTALL_DIR')) {
  9041.     define('PEAR_CONFIG_DEFAULT_PHP_DIR', getenv('PHP_PEAR_INSTALL_DIR'));
  9042. } else {
  9043.     if (file_exists($PEAR_INSTALL_DIR) && is_dir($PEAR_INSTALL_DIR)) {
  9044.         define('PEAR_CONFIG_DEFAULT_PHP_DIR',
  9045.                $PEAR_INSTALL_DIR);
  9046.     } else {
  9047.         define('PEAR_CONFIG_DEFAULT_PHP_DIR', $PEAR_INSTALL_DIR);
  9048.     }
  9049. }
  9050.  
  9051. // Default for ext_dir
  9052. if (getenv('PHP_PEAR_EXTENSION_DIR')) {
  9053.     define('PEAR_CONFIG_DEFAULT_EXT_DIR', getenv('PHP_PEAR_EXTENSION_DIR'));
  9054. } else {
  9055.     if (ini_get('extension_dir')) {
  9056.         define('PEAR_CONFIG_DEFAULT_EXT_DIR', ini_get('extension_dir'));
  9057.     } elseif (defined('PEAR_EXTENSION_DIR') &&
  9058.               file_exists(PEAR_EXTENSION_DIR) && is_dir(PEAR_EXTENSION_DIR)) {
  9059.         define('PEAR_CONFIG_DEFAULT_EXT_DIR', PEAR_EXTENSION_DIR);
  9060.     } elseif (defined('PHP_EXTENSION_DIR')) {
  9061.         define('PEAR_CONFIG_DEFAULT_EXT_DIR', PHP_EXTENSION_DIR);
  9062.     } else {
  9063.         define('PEAR_CONFIG_DEFAULT_EXT_DIR', '.');
  9064.     }
  9065. }
  9066.  
  9067. // Default for doc_dir
  9068. if (getenv('PHP_PEAR_DOC_DIR')) {
  9069.     define('PEAR_CONFIG_DEFAULT_DOC_DIR', getenv('PHP_PEAR_DOC_DIR'));
  9070. } else {
  9071.     define('PEAR_CONFIG_DEFAULT_DOC_DIR',
  9072.            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'docs');
  9073. }
  9074.  
  9075. // Default for bin_dir
  9076. if (getenv('PHP_PEAR_BIN_DIR')) {
  9077.     define('PEAR_CONFIG_DEFAULT_BIN_DIR', getenv('PHP_PEAR_BIN_DIR'));
  9078. } else {
  9079.     define('PEAR_CONFIG_DEFAULT_BIN_DIR', PHP_BINDIR);
  9080. }
  9081.  
  9082. // Default for data_dir
  9083. if (getenv('PHP_PEAR_DATA_DIR')) {
  9084.     define('PEAR_CONFIG_DEFAULT_DATA_DIR', getenv('PHP_PEAR_DATA_DIR'));
  9085. } else {
  9086.     define('PEAR_CONFIG_DEFAULT_DATA_DIR',
  9087.            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'data');
  9088. }
  9089.  
  9090. // Default for test_dir
  9091. if (getenv('PHP_PEAR_TEST_DIR')) {
  9092.     define('PEAR_CONFIG_DEFAULT_TEST_DIR', getenv('PHP_PEAR_TEST_DIR'));
  9093. } else {
  9094.     define('PEAR_CONFIG_DEFAULT_TEST_DIR',
  9095.            $PEAR_INSTALL_DIR.DIRECTORY_SEPARATOR.'tests');
  9096. }
  9097.  
  9098. // Default for temp_dir
  9099. if (getenv('PHP_PEAR_TEMP_DIR')) {
  9100.     define('PEAR_CONFIG_DEFAULT_TEMP_DIR', getenv('PHP_PEAR_TEMP_DIR'));
  9101. } else {
  9102.     define('PEAR_CONFIG_DEFAULT_TEMP_DIR',
  9103.            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9104.            DIRECTORY_SEPARATOR . 'temp');
  9105. }
  9106.  
  9107. // Default for cache_dir
  9108. if (getenv('PHP_PEAR_CACHE_DIR')) {
  9109.     define('PEAR_CONFIG_DEFAULT_CACHE_DIR', getenv('PHP_PEAR_CACHE_DIR'));
  9110. } else {
  9111.     define('PEAR_CONFIG_DEFAULT_CACHE_DIR',
  9112.            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9113.            DIRECTORY_SEPARATOR . 'cache');
  9114. }
  9115.  
  9116. // Default for download_dir
  9117. if (getenv('PHP_PEAR_DOWNLOAD_DIR')) {
  9118.     define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR', getenv('PHP_PEAR_DOWNLOAD_DIR'));
  9119. } else {
  9120.     define('PEAR_CONFIG_DEFAULT_DOWNLOAD_DIR',
  9121.            System::tmpdir() . DIRECTORY_SEPARATOR . 'pear' .
  9122.            DIRECTORY_SEPARATOR . 'download');
  9123. }
  9124.  
  9125. // Default for php_bin
  9126. if (getenv('PHP_PEAR_PHP_BIN')) {
  9127.     define('PEAR_CONFIG_DEFAULT_PHP_BIN', getenv('PHP_PEAR_PHP_BIN'));
  9128. } else {
  9129.     define('PEAR_CONFIG_DEFAULT_PHP_BIN', PEAR_CONFIG_DEFAULT_BIN_DIR.
  9130.            DIRECTORY_SEPARATOR.'php'.(OS_WINDOWS ? '.exe' : ''));
  9131. }
  9132.  
  9133. // Default for verbose
  9134. if (getenv('PHP_PEAR_VERBOSE')) {
  9135.     define('PEAR_CONFIG_DEFAULT_VERBOSE', getenv('PHP_PEAR_VERBOSE'));
  9136. } else {
  9137.     define('PEAR_CONFIG_DEFAULT_VERBOSE', 1);
  9138. }
  9139.  
  9140. // Default for preferred_state
  9141. if (getenv('PHP_PEAR_PREFERRED_STATE')) {
  9142.     define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', getenv('PHP_PEAR_PREFERRED_STATE'));
  9143. } else {
  9144.     define('PEAR_CONFIG_DEFAULT_PREFERRED_STATE', 'stable');
  9145. }
  9146.  
  9147. // Default for umask
  9148. if (getenv('PHP_PEAR_UMASK')) {
  9149.     define('PEAR_CONFIG_DEFAULT_UMASK', getenv('PHP_PEAR_UMASK'));
  9150. } else {
  9151.     define('PEAR_CONFIG_DEFAULT_UMASK', decoct(umask()));
  9152. }
  9153.  
  9154. // Default for cache_ttl
  9155. if (getenv('PHP_PEAR_CACHE_TTL')) {
  9156.     define('PEAR_CONFIG_DEFAULT_CACHE_TTL', getenv('PHP_PEAR_CACHE_TTL'));
  9157. } else {
  9158.     define('PEAR_CONFIG_DEFAULT_CACHE_TTL', 3600);
  9159. }
  9160.  
  9161. // Default for sig_type
  9162. if (getenv('PHP_PEAR_SIG_TYPE')) {
  9163.     define('PEAR_CONFIG_DEFAULT_SIG_TYPE', getenv('PHP_PEAR_SIG_TYPE'));
  9164. } else {
  9165.     define('PEAR_CONFIG_DEFAULT_SIG_TYPE', 'gpg');
  9166. }
  9167.  
  9168. // Default for sig_bin
  9169. if (getenv('PHP_PEAR_SIG_BIN')) {
  9170.     define('PEAR_CONFIG_DEFAULT_SIG_BIN', getenv('PHP_PEAR_SIG_BIN'));
  9171. } else {
  9172.     define('PEAR_CONFIG_DEFAULT_SIG_BIN',
  9173.            System::which(
  9174.                'gpg', OS_WINDOWS ? 'c:\gnupg\gpg.exe' : '/usr/local/bin/gpg'));
  9175. }
  9176.  
  9177. // Default for sig_keydir
  9178. if (getenv('PHP_PEAR_SIG_KEYDIR')) {
  9179.     define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR', getenv('PHP_PEAR_SIG_KEYDIR'));
  9180. } else {
  9181.     define('PEAR_CONFIG_DEFAULT_SIG_KEYDIR',
  9182.            PEAR_CONFIG_SYSCONFDIR . DIRECTORY_SEPARATOR . 'pearkeys');
  9183. }
  9184.  
  9185. /**
  9186.  * This is a class for storing configuration data, keeping track of
  9187.  * which are system-defined, user-defined or defaulted.
  9188.  * @category   pear
  9189.  * @package    PEAR
  9190.  * @author     Stig Bakken <ssb@php.net>
  9191.  * @author     Greg Beaver <cellog@php.net>
  9192.  * @copyright  1997-2006 The PHP Group
  9193.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  9194.  * @version    Release: @package_version@
  9195.  * @link       http://pear.php.net/package/PEAR
  9196.  * @since      Class available since Release 0.1
  9197.  */
  9198. class PEAR_Config extends PEAR
  9199. {
  9200.     // {{{ properties
  9201.  
  9202.     /**
  9203.      * Array of config files used.
  9204.      *
  9205.      * @var array layer => config file
  9206.      */
  9207.     var $files = array(
  9208.         'system' => '',
  9209.         'user' => '',
  9210.         );
  9211.  
  9212.     var $layers = array();
  9213.     
  9214.     /**
  9215.      * Configuration data, two-dimensional array where the first
  9216.      * dimension is the config layer ('user', 'system' and 'default'),
  9217.      * and the second dimension is keyname => value.
  9218.      *
  9219.      * The order in the first dimension is important!  Earlier
  9220.      * layers will shadow later ones when a config value is
  9221.      * requested (if a 'user' value exists, it will be returned first,
  9222.      * then 'system' and finally 'default').
  9223.      *
  9224.      * @var array layer => array(keyname => value, ...)
  9225.      */
  9226.     var $configuration = array(
  9227.         'user' => array(),
  9228.         'system' => array(),
  9229.         'default' => array(),
  9230.         );
  9231.     
  9232.     /**
  9233.      * Configuration values that can be set for a channel
  9234.      *
  9235.      * All other configuration values can only have a global value
  9236.      * @var array
  9237.      * @access private
  9238.      */
  9239.     var $_channelConfigInfo = array(
  9240.         'php_dir', 'ext_dir', 'doc_dir', 'bin_dir', 'data_dir',
  9241.         'test_dir', 'php_bin', 'username', 'password', 'verbose',
  9242.         'preferred_state', 'umask', 'preferred_mirror',
  9243.         );
  9244.  
  9245.     /**
  9246.      * Channels that can be accessed
  9247.      * @see setChannels()
  9248.      * @var array
  9249.      * @access private
  9250.      */
  9251.     var $_channels = array('pear.php.net', 'pecl.php.net', '__uri');
  9252.  
  9253.     /**
  9254.      * This variable is used to control the directory values returned
  9255.      * @see setInstallRoot();
  9256.      * @var string|false
  9257.      * @access private
  9258.      */
  9259.     var $_installRoot = false;
  9260.  
  9261.     /**
  9262.      * If requested, this will always refer to the registry
  9263.      * contained in php_dir
  9264.      * @var PEAR_Registry
  9265.      */
  9266.     var $_registry = array();
  9267.  
  9268.     /**
  9269.      * @var array
  9270.      * @access private
  9271.      */
  9272.     var $_regInitialized = array();
  9273.  
  9274.     /**
  9275.      * @var bool
  9276.      * @access private
  9277.      */
  9278.     var $_noRegistry = false;
  9279.  
  9280.     /**
  9281.      * amount of errors found while parsing config
  9282.      * @var integer
  9283.      * @access private
  9284.      */
  9285.     var $_errorsFound = 0;
  9286.     var $_lastError = null;
  9287.  
  9288.     /**
  9289.      * Information about the configuration data.  Stores the type,
  9290.      * default value and a documentation string for each configuration
  9291.      * value.
  9292.      *
  9293.      * @var array layer => array(infotype => value, ...)
  9294.      */
  9295.     var $configuration_info = array(
  9296.         // Channels/Internet Access
  9297.         'default_channel' => array(
  9298.             'type' => 'string',
  9299.             'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
  9300.             'doc' => 'the default channel to use for all non explicit commands',
  9301.             'prompt' => 'Default Channel',
  9302.             'group' => 'Internet Access',
  9303.             ),
  9304.         'preferred_mirror' => array(
  9305.             'type' => 'string',
  9306.             'default' => PEAR_CONFIG_DEFAULT_CHANNEL,
  9307.             'doc' => 'the default server or mirror to use for channel actions',
  9308.             'prompt' => 'Default Channel Mirror',
  9309.             'group' => 'Internet Access',
  9310.             ),
  9311.         'remote_config' => array(
  9312.             'type' => 'password',
  9313.             'default' => '',
  9314.             'doc' => 'ftp url of remote configuration file to use for synchronized install',
  9315.             'prompt' => 'Remote Configuration File',
  9316.             'group' => 'Internet Access',
  9317.             ),
  9318.         'auto_discover' => array(
  9319.             'type' => 'integer',
  9320.             'default' => 0,
  9321.             'doc' => 'whether to automatically discover new channels',
  9322.             'prompt' => 'Auto-discover new Channels',
  9323.             'group' => 'Internet Access',
  9324.             ),
  9325.         // Internet Access
  9326.         'master_server' => array(
  9327.             'type' => 'string',
  9328.             'default' => 'pear.php.net',
  9329.             'doc' => 'name of the main PEAR server [NOT USED IN THIS VERSION]',
  9330.             'prompt' => 'PEAR server [DEPRECATED]',
  9331.             'group' => 'Internet Access',
  9332.             ),
  9333.         'http_proxy' => array(
  9334.             'type' => 'string',
  9335.             'default' => PEAR_CONFIG_DEFAULT_HTTP_PROXY,
  9336.             'doc' => 'HTTP proxy (host:port) to use when downloading packages',
  9337.             'prompt' => 'HTTP Proxy Server Address',
  9338.             'group' => 'Internet Access',
  9339.             ),
  9340.         // File Locations
  9341.         'php_dir' => array(
  9342.             'type' => 'directory',
  9343.             'default' => PEAR_CONFIG_DEFAULT_PHP_DIR,
  9344.             'doc' => 'directory where .php files are installed',
  9345.             'prompt' => 'PEAR directory',
  9346.             'group' => 'File Locations',
  9347.             ),
  9348.         'ext_dir' => array(
  9349.             'type' => 'directory',
  9350.             'default' => PEAR_CONFIG_DEFAULT_EXT_DIR,
  9351.             'doc' => 'directory where loadable extensions are installed',
  9352.             'prompt' => 'PHP extension directory',
  9353.             'group' => 'File Locations',
  9354.             ),
  9355.         'doc_dir' => array(
  9356.             'type' => 'directory',
  9357.             'default' => PEAR_CONFIG_DEFAULT_DOC_DIR,
  9358.             'doc' => 'directory where documentation is installed',
  9359.             'prompt' => 'PEAR documentation directory',
  9360.             'group' => 'File Locations',
  9361.             ),
  9362.         'bin_dir' => array(
  9363.             'type' => 'directory',
  9364.             'default' => PEAR_CONFIG_DEFAULT_BIN_DIR,
  9365.             'doc' => 'directory where executables are installed',
  9366.             'prompt' => 'PEAR executables directory',
  9367.             'group' => 'File Locations',
  9368.             ),
  9369.         'data_dir' => array(
  9370.             'type' => 'directory',
  9371.             'default' => PEAR_CONFIG_DEFAULT_DATA_DIR,
  9372.             'doc' => 'directory where data files are installed',
  9373.             'prompt' => 'PEAR data directory',
  9374.             'group' => 'File Locations (Advanced)',
  9375.             ),
  9376.         'test_dir' => array(
  9377.             'type' => 'directory',
  9378.             'default' => PEAR_CONFIG_DEFAULT_TEST_DIR,
  9379.             'doc' => 'directory where regression tests are installed',
  9380.             'prompt' => 'PEAR test directory',
  9381.             'group' => 'File Locations (Advanced)',
  9382.             ),
  9383.         'cache_dir' => array(
  9384.             'type' => 'directory',
  9385.             'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR,
  9386.             'doc' => 'directory which is used for XMLRPC cache',
  9387.             'prompt' => 'PEAR Installer cache directory',
  9388.             'group' => 'File Locations (Advanced)',
  9389.             ),
  9390.         'temp_dir' => array(
  9391.             'type' => 'directory',
  9392.             'default' => PEAR_CONFIG_DEFAULT_TEMP_DIR,
  9393.             'doc' => 'directory which is used for all temp files',
  9394.             'prompt' => 'PEAR Installer temp directory',
  9395.             'group' => 'File Locations (Advanced)',
  9396.             ),
  9397.         'download_dir' => array(
  9398.             'type' => 'directory',
  9399.             'default' => PEAR_CONFIG_DEFAULT_CACHE_DIR,
  9400.             'doc' => 'directory which is used for all downloaded files',
  9401.             'prompt' => 'PEAR Installer download directory',
  9402.             'group' => 'File Locations (Advanced)',
  9403.             ),
  9404.         'php_bin' => array(
  9405.             'type' => 'file',
  9406.             'default' => PEAR_CONFIG_DEFAULT_PHP_BIN,
  9407.             'doc' => 'PHP CLI/CGI binary for executing scripts',
  9408.             'prompt' => 'PHP CLI/CGI binary',
  9409.             'group' => 'File Locations (Advanced)',
  9410.             ),
  9411.         'php_ini' => array(
  9412.             'type' => 'file',
  9413.             'default' => '',
  9414.             'doc' => 'location of php.ini in which to enable PECL extensions on install',
  9415.             'prompt' => 'php.ini location',
  9416.             'group' => 'File Locations (Advanced)',
  9417.             ),
  9418.         // Maintainers
  9419.         'username' => array(
  9420.             'type' => 'string',
  9421.             'default' => '',
  9422.             'doc' => '(maintainers) your PEAR account name',
  9423.             'prompt' => 'PEAR username (for maintainers)',
  9424.             'group' => 'Maintainers',
  9425.             ),
  9426.         'password' => array(
  9427.             'type' => 'password',
  9428.             'default' => '',
  9429.             'doc' => '(maintainers) your PEAR account password',
  9430.             'prompt' => 'PEAR password (for maintainers)',
  9431.             'group' => 'Maintainers',
  9432.             ),
  9433.         // Advanced
  9434.         'verbose' => array(
  9435.             'type' => 'integer',
  9436.             'default' => PEAR_CONFIG_DEFAULT_VERBOSE,
  9437.             'doc' => 'verbosity level
  9438. 0: really quiet
  9439. 1: somewhat quiet
  9440. 2: verbose
  9441. 3: debug',
  9442.             'prompt' => 'Debug Log Level',
  9443.             'group' => 'Advanced',
  9444.             ),
  9445.         'preferred_state' => array(
  9446.             'type' => 'set',
  9447.             'default' => PEAR_CONFIG_DEFAULT_PREFERRED_STATE,
  9448.             'doc' => 'the installer will prefer releases with this state when installing packages without a version or state specified',
  9449.             'valid_set' => array(
  9450.                 'stable', 'beta', 'alpha', 'devel', 'snapshot'),
  9451.             'prompt' => 'Preferred Package State',
  9452.             'group' => 'Advanced',
  9453.             ),
  9454.         'umask' => array(
  9455.             'type' => 'mask',
  9456.             'default' => PEAR_CONFIG_DEFAULT_UMASK,
  9457.             'doc' => 'umask used when creating files (Unix-like systems only)',
  9458.             'prompt' => 'Unix file mask',
  9459.             'group' => 'Advanced',
  9460.             ),
  9461.         'cache_ttl' => array(
  9462.             'type' => 'integer',
  9463.             'default' => PEAR_CONFIG_DEFAULT_CACHE_TTL,
  9464.             'doc' => 'amount of secs where the local cache is used and not updated',
  9465.             'prompt' => 'Cache TimeToLive',
  9466.             'group' => 'Advanced',
  9467.             ),
  9468.         'sig_type' => array(
  9469.             'type' => 'set',
  9470.             'default' => PEAR_CONFIG_DEFAULT_SIG_TYPE,
  9471.             'doc' => 'which package signature mechanism to use',
  9472.             'valid_set' => array('gpg'),
  9473.             'prompt' => 'Package Signature Type',
  9474.             'group' => 'Maintainers',
  9475.             ),
  9476.         'sig_bin' => array(
  9477.             'type' => 'string',
  9478.             'default' => PEAR_CONFIG_DEFAULT_SIG_BIN,
  9479.             'doc' => 'which package signature mechanism to use',
  9480.             'prompt' => 'Signature Handling Program',
  9481.             'group' => 'Maintainers',
  9482.             ),
  9483.         'sig_keyid' => array(
  9484.             'type' => 'string',
  9485.             'default' => '',
  9486.             'doc' => 'which key to use for signing with',
  9487.             'prompt' => 'Signature Key Id',
  9488.             'group' => 'Maintainers',
  9489.             ),
  9490.         'sig_keydir' => array(
  9491.             'type' => 'directory',
  9492.             'default' => PEAR_CONFIG_DEFAULT_SIG_KEYDIR,
  9493.             'doc' => 'directory where signature keys are located',
  9494.             'prompt' => 'Signature Key Directory',
  9495.             'group' => 'Maintainers',
  9496.             ),
  9497.         // __channels is reserved - used for channel-specific configuration
  9498.         );
  9499.  
  9500.     // }}}
  9501.  
  9502.     // {{{ PEAR_Config([file], [defaults_file])
  9503.  
  9504.     /**
  9505.      * Constructor.
  9506.      *
  9507.      * @param string file to read user-defined options from
  9508.      * @param string file to read system-wide defaults from
  9509.      * @param bool   determines whether a registry object "follows"
  9510.      *               the value of php_dir (is automatically created
  9511.      *               and moved when php_dir is changed)
  9512.      * @param bool   if true, fails if configuration files cannot be loaded
  9513.      *
  9514.      * @access public
  9515.      *
  9516.      * @see PEAR_Config::singleton
  9517.      */
  9518.     function PEAR_Config($user_file = '', $system_file = '', $ftp_file = false,
  9519.                          $strict = true)
  9520.     {
  9521.         $this->PEAR();
  9522.         PEAR_Installer_Role::initializeConfig($this);
  9523.         $sl = DIRECTORY_SEPARATOR;
  9524.         if (empty($user_file)) {
  9525.             if (OS_WINDOWS) {
  9526.                 $user_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.ini';
  9527.             } else {
  9528.                 $user_file = getenv('HOME') . $sl . '.pearrc';
  9529.             }
  9530.         }
  9531.         if (empty($system_file)) {
  9532.             if (OS_WINDOWS) {
  9533.                 $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pearsys.ini';
  9534.             } else {
  9535.                 $system_file = PEAR_CONFIG_SYSCONFDIR . $sl . 'pear.conf';
  9536.             }
  9537.         }
  9538.  
  9539.         $this->layers = array_keys($this->configuration);
  9540.         $this->files['user'] = $user_file;
  9541.         $this->files['system'] = $system_file;
  9542.         if ($user_file && file_exists($user_file)) {
  9543.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  9544.             $this->readConfigFile($user_file, 'user', $strict);
  9545.             $this->popErrorHandling();
  9546.             if ($this->_errorsFound > 0) {
  9547.                 return;
  9548.             }
  9549.         }
  9550.  
  9551.         if ($system_file && file_exists($system_file)) {
  9552.             $this->mergeConfigFile($system_file, false, 'system', $strict);
  9553.             if ($this->_errorsFound > 0) {
  9554.                 return;
  9555.             }
  9556.  
  9557.         }
  9558.  
  9559.         if (!$ftp_file) {
  9560.             $ftp_file = $this->get('remote_config');
  9561.         }
  9562.  
  9563.         if ($ftp_file && defined('PEAR_REMOTEINSTALL_OK')) {
  9564.             $this->readFTPConfigFile($ftp_file);
  9565.         }
  9566.  
  9567.         foreach ($this->configuration_info as $key => $info) {
  9568.             $this->configuration['default'][$key] = $info['default'];
  9569.         }
  9570.  
  9571.         $this->_registry['default'] = &new PEAR_Registry($this->configuration['default']['php_dir']);
  9572.         $this->_registry['default']->setConfig($this);
  9573.         $this->_regInitialized['default'] = false;
  9574.         //$GLOBALS['_PEAR_Config_instance'] = &$this;
  9575.     }
  9576.  
  9577.     // }}}
  9578.     // {{{ singleton([file], [defaults_file])
  9579.  
  9580.     /**
  9581.      * Static singleton method.  If you want to keep only one instance
  9582.      * of this class in use, this method will give you a reference to
  9583.      * the last created PEAR_Config object if one exists, or create a
  9584.      * new object.
  9585.      *
  9586.      * @param string (optional) file to read user-defined options from
  9587.      * @param string (optional) file to read system-wide defaults from
  9588.      *
  9589.      * @return object an existing or new PEAR_Config instance
  9590.      *
  9591.      * @access public
  9592.      *
  9593.      * @see PEAR_Config::PEAR_Config
  9594.      */
  9595.     function &singleton($user_file = '', $system_file = '', $strict = true)
  9596.     {
  9597.         if (is_object($GLOBALS['_PEAR_Config_instance'])) {
  9598.             return $GLOBALS['_PEAR_Config_instance'];
  9599.         }
  9600.  
  9601.         $t_conf = &new PEAR_Config($user_file, $system_file, false, $strict);
  9602.         if ($t_conf->_errorsFound > 0) {
  9603.              return $t_conf->lastError;
  9604.         }
  9605.  
  9606.         $GLOBALS['_PEAR_Config_instance'] = &$t_conf;
  9607.         return $GLOBALS['_PEAR_Config_instance'];
  9608.     }
  9609.  
  9610.     // }}}
  9611.     // {{{ validConfiguration()
  9612.  
  9613.     /**
  9614.      * Determine whether any configuration files have been detected, and whether a
  9615.      * registry object can be retrieved from this configuration.
  9616.      * @return bool
  9617.      * @since PEAR 1.4.0a1
  9618.      */
  9619.     function validConfiguration()
  9620.     {
  9621.         if ($this->isDefinedLayer('user') || $this->isDefinedLayer('system')) {
  9622.             return true;
  9623.         }
  9624.         return false;
  9625.     }
  9626.  
  9627.     // }}}
  9628.     // {{{ readConfigFile([file], [layer])
  9629.  
  9630.     /**
  9631.      * Reads configuration data from a file.  All existing values in
  9632.      * the config layer are discarded and replaced with data from the
  9633.      * file.
  9634.      * @param string file to read from, if NULL or not specified, the
  9635.      *               last-used file for the same layer (second param) is used
  9636.      * @param string config layer to insert data into ('user' or 'system')
  9637.      * @return bool TRUE on success or a PEAR error on failure
  9638.      */
  9639.     function readConfigFile($file = null, $layer = 'user', $strict = true)
  9640.     {
  9641.         if (empty($this->files[$layer])) {
  9642.             return $this->raiseError("unknown config layer `$layer'");
  9643.         }
  9644.  
  9645.         if ($file === null) {
  9646.             $file = $this->files[$layer];
  9647.         }
  9648.  
  9649.         $data = $this->_readConfigDataFrom($file);
  9650.  
  9651.         if (PEAR::isError($data)) {
  9652.             if ($strict) {
  9653.                 $this->_errorsFound++;
  9654.                 $this->lastError = $data;
  9655.  
  9656.                 return $data;
  9657.             } else {
  9658.                 return true;
  9659.             }
  9660.         } else {
  9661.             $this->files[$layer] = $file;
  9662.         }
  9663.  
  9664.         $this->_decodeInput($data);
  9665.         $this->configuration[$layer] = $data;
  9666.         $this->_setupChannels();
  9667.         if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
  9668.             $this->_registry[$layer] = &new PEAR_Registry($phpdir);
  9669.             $this->_registry[$layer]->setConfig($this);
  9670.             $this->_regInitialized[$layer] = false;
  9671.         } else {
  9672.             unset($this->_registry[$layer]);
  9673.         }
  9674.         return true;
  9675.     }
  9676.  
  9677.     // }}}
  9678.  
  9679.     /**
  9680.      * @param string url to the remote config file, like ftp://www.example.com/pear/config.ini
  9681.      * @return true|PEAR_Error
  9682.      */
  9683.     function readFTPConfigFile($path)
  9684.     {
  9685.         do { // poor man's try
  9686.             if (!class_exists('PEAR_FTP')) {
  9687.                 if (!class_exists('PEAR_Common')) {
  9688.                     require_once 'phar://go-pear.phar/PEAR/Common.php';
  9689.                 }
  9690.                 if (PEAR_Common::isIncludeable('PEAR/FTP.php')) {
  9691.                     require_once 'phar://go-pear.phar/PEAR/FTP.php';
  9692.                 }
  9693.             }
  9694.             if (class_exists('PEAR_FTP')) {
  9695.                 $this->_ftp = &new PEAR_FTP;
  9696.                 $this->_ftp->pushErrorHandling(PEAR_ERROR_RETURN);
  9697.                 $e = $this->_ftp->init($path);
  9698.                 if (PEAR::isError($e)) {
  9699.                     $this->_ftp->popErrorHandling();
  9700.                     return $e;
  9701.                 }
  9702.                 $tmp = System::mktemp('-d');
  9703.                 PEAR_Common::addTempFile($tmp);
  9704.                 $e = $this->_ftp->get(basename($path), $tmp . DIRECTORY_SEPARATOR .
  9705.                     'pear.ini', false, FTP_BINARY);
  9706.                 if (PEAR::isError($e)) {
  9707.                     $this->_ftp->popErrorHandling();
  9708.                     return $e;
  9709.                 }
  9710.                 PEAR_Common::addTempFile($tmp . DIRECTORY_SEPARATOR . 'pear.ini');
  9711.                 $this->_ftp->disconnect();
  9712.                 $this->_ftp->popErrorHandling();
  9713.                 $this->files['ftp'] = $tmp . DIRECTORY_SEPARATOR . 'pear.ini';
  9714.                 $e = $this->readConfigFile(null, 'ftp');
  9715.                 if (PEAR::isError($e)) {
  9716.                     return $e;
  9717.                 }
  9718.                 $fail = array();
  9719.                 foreach ($this->configuration_info as $key => $val) {
  9720.                     if (in_array($this->getGroup($key),
  9721.                           array('File Locations', 'File Locations (Advanced)')) &&
  9722.                           $this->getType($key) == 'directory') {
  9723.                         // any directory configs must be set for this to work
  9724.                         if (!isset($this->configuration['ftp'][$key])) {
  9725.                             $fail[] = $key;
  9726.                         }
  9727.                     }
  9728.                 }
  9729.                 if (count($fail)) {
  9730.                     $fail = '"' . implode('", "', $fail) . '"';
  9731.                     unset($this->files['ftp']);
  9732.                     unset($this->configuration['ftp']);
  9733.                     return PEAR::raiseError('ERROR: Ftp configuration file must set all ' .
  9734.                         'directory configuration variables.  These variables were not set: ' .
  9735.                         $fail);
  9736.                 } else {
  9737.                     return true;
  9738.                 }
  9739.             } else {
  9740.                 return PEAR::raiseError('Net_FTP must be installed to use remote config');
  9741.             }
  9742.         } while (false); // poor man's catch
  9743.         unset($this->files['ftp']);
  9744.         return PEAR::raiseError('no remote host specified');
  9745.     }
  9746.  
  9747.     // {{{ _setupChannels()
  9748.     
  9749.     /**
  9750.      * Reads the existing configurations and creates the _channels array from it
  9751.      */
  9752.     function _setupChannels()
  9753.     {
  9754.         $set = array_flip(array_values($this->_channels));
  9755.         foreach ($this->configuration as $layer => $data) {
  9756.             $i = 1000;
  9757.             if (isset($data['__channels']) && is_array($data['__channels'])) {
  9758.                 foreach ($data['__channels'] as $channel => $info) {
  9759.                     $set[$channel] = $i++;
  9760.                 }
  9761.             }
  9762.         }
  9763.         $this->_channels = array_values(array_flip($set));
  9764.         $this->setChannels($this->_channels);
  9765.     }
  9766.  
  9767.     // }}}
  9768.     // {{{ deleteChannel(channel)
  9769.  
  9770.     function deleteChannel($channel)
  9771.     {
  9772.         foreach ($this->configuration as $layer => $data) {
  9773.             if (isset($data['__channels'])) {
  9774.                 if (isset($data['__channels'][strtolower($channel)])) {
  9775.                     unset($this->configuration[$layer]['__channels'][strtolower($channel)]);
  9776.                 }
  9777.             }
  9778.         }
  9779.         $this->_channels = array_flip($this->_channels);
  9780.         unset($this->_channels[strtolower($channel)]);
  9781.         $this->_channels = array_flip($this->_channels);
  9782.     }
  9783.  
  9784.     // }}}
  9785.     // {{{ mergeConfigFile(file, [override], [layer])
  9786.  
  9787.     /**
  9788.      * Merges data into a config layer from a file.  Does the same
  9789.      * thing as readConfigFile, except it does not replace all
  9790.      * existing values in the config layer.
  9791.      * @param string file to read from
  9792.      * @param bool whether to overwrite existing data (default TRUE)
  9793.      * @param string config layer to insert data into ('user' or 'system')
  9794.      * @param string if true, errors are returned if file opening fails
  9795.      * @return bool TRUE on success or a PEAR error on failure
  9796.      */
  9797.     function mergeConfigFile($file, $override = true, $layer = 'user', $strict = true)
  9798.     {
  9799.         if (empty($this->files[$layer])) {
  9800.             return $this->raiseError("unknown config layer `$layer'");
  9801.         }
  9802.         if ($file === null) {
  9803.             $file = $this->files[$layer];
  9804.         }
  9805.         $data = $this->_readConfigDataFrom($file);
  9806.         if (PEAR::isError($data)) {
  9807.             if ($strict) {
  9808.                 $this->_errorsFound++;
  9809.                 $this->lastError = $data;
  9810.  
  9811.                 return $data;
  9812.             } else {
  9813.                 return true;
  9814.             }
  9815.         }
  9816.         $this->_decodeInput($data);
  9817.         if ($override) {
  9818.             $this->configuration[$layer] =
  9819.                 PEAR_Config::arrayMergeRecursive($this->configuration[$layer], $data);
  9820.         } else {
  9821.             $this->configuration[$layer] =
  9822.                 PEAR_Config::arrayMergeRecursive($data, $this->configuration[$layer]);
  9823.         }
  9824.         $this->_setupChannels();
  9825.         if (!$this->_noRegistry && ($phpdir = $this->get('php_dir', $layer, 'pear.php.net'))) {
  9826.             $this->_registry[$layer] = &new PEAR_Registry($phpdir);
  9827.             $this->_registry[$layer]->setConfig($this);
  9828.             $this->_regInitialized[$layer] = false;
  9829.         } else {
  9830.             unset($this->_registry[$layer]);
  9831.         }
  9832.         return true;
  9833.     }
  9834.  
  9835.     // }}}
  9836.     // {{{ arrayMergeRecursive($arr2, $arr1)
  9837.     /**
  9838.      * @param array
  9839.      * @param array
  9840.      * @return array
  9841.      * @static
  9842.      */
  9843.     function arrayMergeRecursive($arr2, $arr1)
  9844.     {
  9845.         $ret = array();
  9846.         foreach ($arr2 as $key => $data) {
  9847.             if (!isset($arr1[$key])) {
  9848.                 $ret[$key] = $data;
  9849.                 unset($arr1[$key]);
  9850.                 continue;
  9851.             }
  9852.             if (is_array($data)) {
  9853.                 if (!is_array($arr1[$key])) {
  9854.                     $ret[$key] = $arr1[$key];
  9855.                     unset($arr1[$key]);
  9856.                     continue;
  9857.                 }
  9858.                 $ret[$key] = PEAR_Config::arrayMergeRecursive($arr1[$key], $arr2[$key]);
  9859.                 unset($arr1[$key]);
  9860.             }
  9861.         }
  9862.         return array_merge($ret, $arr1);
  9863.     }
  9864.  
  9865.     // }}}
  9866.     // {{{ writeConfigFile([file], [layer])
  9867.  
  9868.     /**
  9869.      * Writes data into a config layer from a file.
  9870.      *
  9871.      * @param string|null file to read from, or null for default
  9872.      * @param string config layer to insert data into ('user' or
  9873.      *               'system')
  9874.      * @param string|null data to write to config file or null for internal data [DEPRECATED]
  9875.      * @return bool TRUE on success or a PEAR error on failure
  9876.      */
  9877.     function writeConfigFile($file = null, $layer = 'user', $data = null)
  9878.     {
  9879.         $this->_lazyChannelSetup($layer);
  9880.         if ($layer == 'both' || $layer == 'all') {
  9881.             foreach ($this->files as $type => $file) {
  9882.                 $err = $this->writeConfigFile($file, $type, $data);
  9883.                 if (PEAR::isError($err)) {
  9884.                     return $err;
  9885.                 }
  9886.             }
  9887.             return true;
  9888.         }
  9889.         if (empty($this->files[$layer])) {
  9890.             return $this->raiseError("unknown config file type `$layer'");
  9891.         }
  9892.         if ($file === null) {
  9893.             $file = $this->files[$layer];
  9894.         }
  9895.         $data = ($data === null) ? $this->configuration[$layer] : $data;
  9896.         $this->_encodeOutput($data);
  9897.         $opt = array('-p', dirname($file));
  9898.         if (!@System::mkDir($opt)) {
  9899.             return $this->raiseError("could not create directory: " . dirname($file));
  9900.         }
  9901.         if (file_exists($file) && is_file($file) && !is_writeable($file)) {
  9902.             return $this->raiseError("no write access to $file!");
  9903.         }
  9904.         $fp = @fopen($file, "w");
  9905.         if (!$fp) {
  9906.             return $this->raiseError("PEAR_Config::writeConfigFile fopen('$file','w') failed ($php_errormsg)");
  9907.         }
  9908.         $contents = "#PEAR_Config 0.9\n" . serialize($data);
  9909.         if (!@fwrite($fp, $contents)) {
  9910.             return $this->raiseError("PEAR_Config::writeConfigFile: fwrite failed ($php_errormsg)");
  9911.         }
  9912.         return true;
  9913.     }
  9914.  
  9915.     // }}}
  9916.     // {{{ _readConfigDataFrom(file)
  9917.  
  9918.     /**
  9919.      * Reads configuration data from a file and returns the parsed data
  9920.      * in an array.
  9921.      *
  9922.      * @param string file to read from
  9923.      *
  9924.      * @return array configuration data or a PEAR error on failure
  9925.      *
  9926.      * @access private
  9927.      */
  9928.     function _readConfigDataFrom($file)
  9929.     {
  9930.         $fp = false;
  9931.         if (file_exists($file)) {
  9932.             $fp = @fopen($file, "r");
  9933.         }
  9934.         if (!$fp) {
  9935.             return $this->raiseError("PEAR_Config::readConfigFile fopen('$file','r') failed");
  9936.         }
  9937.         $size = filesize($file);
  9938.         $rt = get_magic_quotes_runtime();
  9939.         set_magic_quotes_runtime(0);
  9940.         fclose($fp);
  9941.         $contents = file_get_contents($file);
  9942.         if (empty($contents)) {
  9943.             return $this->raiseError('Configuration file "' . $file . '" is empty');
  9944.         }
  9945.         
  9946.         set_magic_quotes_runtime($rt);
  9947.  
  9948.         $version = false;
  9949.         if (preg_match('/^#PEAR_Config\s+(\S+)\s+/si', $contents, $matches)) {
  9950.             $version = $matches[1];
  9951.             $contents = substr($contents, strlen($matches[0]));
  9952.         } else {
  9953.             // Museum config file
  9954.             if (substr($contents,0,2) == 'a:') {
  9955.                 $version = '0.1';
  9956.             }
  9957.         }
  9958.         if ($version && version_compare("$version", '1', '<')) {
  9959.  
  9960.             // no '@', it is possible that unserialize
  9961.             // raises a notice but it seems to block IO to
  9962.             // STDOUT if a '@' is used and a notice is raise
  9963.             $data = unserialize($contents);
  9964.  
  9965.             if (!is_array($data) && !$data) {
  9966.                 if ($contents == serialize(false)) {
  9967.                     $data = array();
  9968.                 } else {
  9969.                     $err = $this->raiseError("PEAR_Config: bad data in $file");
  9970.                     return $err;
  9971.                 }
  9972.             }
  9973.             if (!is_array($data)) {
  9974.                 if (strlen(trim($contents)) > 0) {
  9975.                     $error = "PEAR_Config: bad data in $file";
  9976.                     $err = $this->raiseError($error);
  9977.                     return $err;
  9978.                 } else {
  9979.                     $data = array();
  9980.                 }
  9981.             }
  9982.         // add parsing of newer formats here...
  9983.         } else {
  9984.             $err = $this->raiseError("$file: unknown version `$version'");
  9985.             return $err; 
  9986.         }
  9987.         return $data;
  9988.     }
  9989.  
  9990.     // }}}
  9991.     // {{{ getConfFile(layer)
  9992.     /**
  9993.     * Gets the file used for storing the config for a layer
  9994.     *
  9995.     * @param string $layer 'user' or 'system'
  9996.     */
  9997.  
  9998.     function getConfFile($layer)
  9999.     {
  10000.         return $this->files[$layer];
  10001.     }
  10002.  
  10003.     // }}}
  10004.  
  10005.     /**
  10006.      * @param array information on a role as parsed from its xml file
  10007.      * @return true|PEAR_Error
  10008.      * @access private
  10009.      */
  10010.     function _addConfigVars($vars)
  10011.     {
  10012.         if (count($vars) > 3) {
  10013.             return $this->raiseError('Roles can only define 3 new config variables or less');
  10014.         }
  10015.         foreach ($vars as $name => $var) {
  10016.             if (!is_array($var)) {
  10017.                 return $this->raiseError('Configuration information must be an array');
  10018.             }
  10019.             if (!isset($var['type'])) {
  10020.                 return $this->raiseError('Configuration information must contain a type');
  10021.             } else {
  10022.                 if (!in_array($var['type'],
  10023.                       array('string', 'mask', 'password', 'directory', 'file', 'set'))) {
  10024.                     return $this->raiseError(
  10025.                         'Configuration type must be one of directory, file, string, ' .
  10026.                         'mask, set, or password');
  10027.                 }
  10028.             }
  10029.             if (!isset($var['default'])) {
  10030.                 return $this->raiseError(
  10031.                     'Configuration information must contain a default value ("default" index)');
  10032.             } else {
  10033.                 if (is_array($var['default'])) {
  10034.                     $real_default = '';
  10035.                     foreach ($var['default'] as $config_var => $val) {
  10036.                         if (strpos($config_var, 'text') === 0) {
  10037.                             $real_default .= $val;
  10038.                         } elseif (strpos($config_var, 'constant') === 0) {
  10039.                             if (defined($val)) {
  10040.                                 $real_default .= constant($val);
  10041.                             } else {
  10042.                                 return $this->raiseError(
  10043.                                     'Unknown constant "' . $val . '" requested in ' .
  10044.                                     'default value for configuration variable "' .
  10045.                                     $name . '"');
  10046.                             }
  10047.                         } elseif (isset($this->configuration_info[$config_var])) {
  10048.                             $real_default .=
  10049.                                 $this->configuration_info[$config_var]['default'];
  10050.                         } else {
  10051.                             return $this->raiseError(
  10052.                                 'Unknown request for "' . $config_var . '" value in ' .
  10053.                                 'default value for configuration variable "' .
  10054.                                 $name . '"');
  10055.                         }
  10056.                     }
  10057.                     $var['default'] = $real_default;
  10058.                 }
  10059.                 if ($var['type'] == 'integer') {
  10060.                     $var['default'] = (integer) $var['default'];
  10061.                 }
  10062.             }
  10063.             if (!isset($var['doc'])) {
  10064.                 return $this->raiseError(
  10065.                     'Configuration information must contain a summary ("doc" index)');
  10066.             }
  10067.             if (!isset($var['prompt'])) {
  10068.                 return $this->raiseError(
  10069.                     'Configuration information must contain a simple prompt ("prompt" index)');
  10070.             }
  10071.             if (!isset($var['group'])) {
  10072.                 return $this->raiseError(
  10073.                     'Configuration information must contain a simple group ("group" index)');
  10074.             }
  10075.             if (isset($this->configuration_info[$name])) {
  10076.                 return $this->raiseError('Configuration variable "' . $name .
  10077.                     '" already exists');
  10078.             }
  10079.             $this->configuration_info[$name] = $var;
  10080.             // fix bug #7351: setting custom config variable in a channel fails
  10081.             $this->_channelConfigInfo[] = $name;
  10082.         }
  10083.         return true;
  10084.     }
  10085.  
  10086.     // {{{ _encodeOutput(&data)
  10087.  
  10088.     /**
  10089.      * Encodes/scrambles configuration data before writing to files.
  10090.      * Currently, 'password' values will be base64-encoded as to avoid
  10091.      * that people spot cleartext passwords by accident.
  10092.      *
  10093.      * @param array (reference) array to encode values in
  10094.      *
  10095.      * @return bool TRUE on success
  10096.      *
  10097.      * @access private
  10098.      */
  10099.     function _encodeOutput(&$data)
  10100.     {
  10101.         foreach ($data as $key => $value) {
  10102.             if ($key == '__channels') {
  10103.                 foreach ($data['__channels'] as $channel => $blah) {
  10104.                     $this->_encodeOutput($data['__channels'][$channel]);
  10105.                 }
  10106.             }
  10107.             if (!isset($this->configuration_info[$key])) {
  10108.                 continue;
  10109.             }
  10110.             $type = $this->configuration_info[$key]['type'];
  10111.             switch ($type) {
  10112.                 // we base64-encode passwords so they are at least
  10113.                 // not shown in plain by accident
  10114.                 case 'password': {
  10115.                     $data[$key] = base64_encode($data[$key]);
  10116.                     break;
  10117.                 }
  10118.                 case 'mask': {
  10119.                     $data[$key] = octdec($data[$key]);
  10120.                     break;
  10121.                 }
  10122.             }
  10123.         }
  10124.         return true;
  10125.     }
  10126.  
  10127.     // }}}
  10128.     // {{{ _decodeInput(&data)
  10129.  
  10130.     /**
  10131.      * Decodes/unscrambles configuration data after reading from files.
  10132.      *
  10133.      * @param array (reference) array to encode values in
  10134.      *
  10135.      * @return bool TRUE on success
  10136.      *
  10137.      * @access private
  10138.      *
  10139.      * @see PEAR_Config::_encodeOutput
  10140.      */
  10141.     function _decodeInput(&$data)
  10142.     {
  10143.         if (!is_array($data)) {
  10144.             return true;
  10145.         }
  10146.         foreach ($data as $key => $value) {
  10147.             if ($key == '__channels') {
  10148.                 foreach ($data['__channels'] as $channel => $blah) {
  10149.                     $this->_decodeInput($data['__channels'][$channel]);
  10150.                 }
  10151.             }
  10152.             if (!isset($this->configuration_info[$key])) {
  10153.                 continue;
  10154.             }
  10155.             $type = $this->configuration_info[$key]['type'];
  10156.             switch ($type) {
  10157.                 case 'password': {
  10158.                     $data[$key] = base64_decode($data[$key]);
  10159.                     break;
  10160.                 }
  10161.                 case 'mask': {
  10162.                     $data[$key] = decoct($data[$key]);
  10163.                     break;
  10164.                 }
  10165.             }
  10166.         }
  10167.         return true;
  10168.     }
  10169.  
  10170.     // }}}
  10171.     // {{{ getDefaultChannel([layer])
  10172.     /**
  10173.      * Retrieve the default channel.
  10174.      *
  10175.      * On startup, channels are not initialized, so if the default channel is not
  10176.      * pear.php.net, then initialize the config.
  10177.      * @param string registry layer
  10178.      * @return string|false
  10179.      */
  10180.     function getDefaultChannel($layer = null)
  10181.     {
  10182.         $ret = false;
  10183.         if ($layer === null) {
  10184.             foreach ($this->layers as $layer) {
  10185.                 if (isset($this->configuration[$layer]['default_channel'])) {
  10186.                     $ret = $this->configuration[$layer]['default_channel'];
  10187.                     break;
  10188.                 }
  10189.             }
  10190.         } elseif (isset($this->configuration[$layer]['default_channel'])) {
  10191.             $ret = $this->configuration[$layer]['default_channel'];
  10192.         }
  10193.         if ($ret == 'pear.php.net' && defined('PEAR_RUNTYPE') && PEAR_RUNTYPE == 'pecl') {
  10194.             $ret = 'pecl.php.net';
  10195.         }
  10196.         if ($ret) {
  10197.             if ($ret != 'pear.php.net') {
  10198.                 $this->_lazyChannelSetup();
  10199.             }
  10200.             return $ret;
  10201.         }
  10202.         return PEAR_CONFIG_DEFAULT_CHANNEL;
  10203.     }
  10204.  
  10205.     // {{{ get(key, [layer])
  10206.     /**
  10207.      * Returns a configuration value, prioritizing layers as per the
  10208.      * layers property.
  10209.      *
  10210.      * @param string config key
  10211.      *
  10212.      * @return mixed the config value, or NULL if not found
  10213.      *
  10214.      * @access public
  10215.      */
  10216.     function get($key, $layer = null, $channel = false)
  10217.     {
  10218.         if (!isset($this->configuration_info[$key])) {
  10219.             return null;
  10220.         }
  10221.         if ($key == '__channels') {
  10222.             return null;
  10223.         }
  10224.         if ($key == 'default_channel') {
  10225.             return $this->getDefaultChannel($layer);
  10226.         }
  10227.         if (!$channel) {
  10228.             $channel = $this->getDefaultChannel();
  10229.         } elseif ($channel != 'pear.php.net') {
  10230.             $this->_lazyChannelSetup();
  10231.         }
  10232.         $channel = strtolower($channel);
  10233.         
  10234.         $test = (in_array($key, $this->_channelConfigInfo)) ?
  10235.             $this->_getChannelValue($key, $layer, $channel) :
  10236.             null;
  10237.         if ($test !== null) {
  10238.             if ($this->_installRoot) {
  10239.                 if (in_array($this->getGroup($key),
  10240.                       array('File Locations', 'File Locations (Advanced)')) &&
  10241.                       $this->getType($key) == 'directory') {
  10242.                     return $this->_prependPath($test, $this->_installRoot);
  10243.                 }
  10244.             }
  10245.             return $test;
  10246.         }
  10247.         if ($layer === null) {
  10248.             foreach ($this->layers as $layer) {
  10249.                 if (isset($this->configuration[$layer][$key])) {
  10250.                     $test = $this->configuration[$layer][$key];
  10251.                     if ($this->_installRoot) {
  10252.                         if (in_array($this->getGroup($key),
  10253.                               array('File Locations', 'File Locations (Advanced)')) &&
  10254.                               $this->getType($key) == 'directory') {
  10255.                             return $this->_prependPath($test, $this->_installRoot);
  10256.                         }
  10257.                     }
  10258.                     if ($key == 'preferred_mirror') {
  10259.                         $reg = &$this->getRegistry();
  10260.                         if (is_object($reg)) {
  10261.                             $chan = &$reg->getChannel($channel);
  10262.                             if (PEAR::isError($chan)) {
  10263.                                 return $channel;
  10264.                             }
  10265.                             if (!$chan->getMirror($test) && $chan->getName() != $test) {
  10266.                                 return $channel; // mirror does not exist
  10267.                             }
  10268.                         }
  10269.                     }
  10270.                     return $test;
  10271.                 }
  10272.             }
  10273.         } elseif (isset($this->configuration[$layer][$key])) {
  10274.             $test = $this->configuration[$layer][$key];
  10275.             if ($this->_installRoot) {
  10276.                 if (in_array($this->getGroup($key),
  10277.                       array('File Locations', 'File Locations (Advanced)')) &&
  10278.                       $this->getType($key) == 'directory') {
  10279.                     return $this->_prependPath($test, $this->_installRoot);
  10280.                 }
  10281.             }
  10282.             if ($key == 'preferred_mirror') {
  10283.                 $reg = &$this->getRegistry();
  10284.                 if (is_object($reg)) {
  10285.                     $chan = &$reg->getChannel($channel);
  10286.                     if (PEAR::isError($chan)) {
  10287.                         return $channel;
  10288.                     }
  10289.                     if (!$chan->getMirror($test) && $chan->getName() != $test) {
  10290.                         return $channel; // mirror does not exist
  10291.                     }
  10292.                 }
  10293.             }
  10294.             return $test;
  10295.         }
  10296.         return null;
  10297.     }
  10298.  
  10299.     // }}}
  10300.     // {{{ _getChannelValue(key, value, [layer])
  10301.     /**
  10302.      * Returns a channel-specific configuration value, prioritizing layers as per the
  10303.      * layers property.
  10304.      *
  10305.      * @param string config key
  10306.      *
  10307.      * @return mixed the config value, or NULL if not found
  10308.      *
  10309.      * @access private
  10310.      */
  10311.     function _getChannelValue($key, $layer, $channel)
  10312.     {
  10313.         if ($key == '__channels' || $channel == 'pear.php.net') {
  10314.             return null;
  10315.         }
  10316.         $ret = null;
  10317.         if ($layer === null) {
  10318.             foreach ($this->layers as $ilayer) {
  10319.                 if (isset($this->configuration[$ilayer]['__channels'][$channel][$key])) {
  10320.                     $ret = $this->configuration[$ilayer]['__channels'][$channel][$key];
  10321.                     break;
  10322.                 }
  10323.             }
  10324.         } elseif (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  10325.             $ret = $this->configuration[$layer]['__channels'][$channel][$key];
  10326.         }
  10327.         if ($key == 'preferred_mirror') {
  10328.             if ($ret !== null) {
  10329.                 $reg = &$this->getRegistry($layer);
  10330.                 if (is_object($reg)) {
  10331.                     $chan = &$reg->getChannel($channel);
  10332.                     if (PEAR::isError($chan)) {
  10333.                         return $channel;
  10334.                     }
  10335.                     if (!$chan->getMirror($ret) && $chan->getName() != $ret) {
  10336.                         return $channel; // mirror does not exist
  10337.                     }
  10338.                 }
  10339.                 return $ret;
  10340.             }
  10341.             if ($channel != $this->getDefaultChannel($layer)) {
  10342.                 return $channel; // we must use the channel name as the preferred mirror
  10343.                                  // if the user has not chosen an alternate
  10344.             } else {
  10345.                 return $this->getDefaultChannel($layer);
  10346.             }
  10347.         }
  10348.         return $ret;
  10349.     }
  10350.  
  10351.  
  10352.     // }}}
  10353.     // {{{ set(key, value, [layer])
  10354.  
  10355.     /**
  10356.      * Set a config value in a specific layer (defaults to 'user').
  10357.      * Enforces the types defined in the configuration_info array.  An
  10358.      * integer config variable will be cast to int, and a set config
  10359.      * variable will be validated against its legal values.
  10360.      *
  10361.      * @param string config key
  10362.      * @param string config value
  10363.      * @param string (optional) config layer
  10364.      * @param string channel to set this value for, or null for global value
  10365.      * @return bool TRUE on success, FALSE on failure
  10366.      */
  10367.     function set($key, $value, $layer = 'user', $channel = false)
  10368.     {
  10369.         if ($key == '__channels') {
  10370.             return false;
  10371.         }
  10372.         if (!isset($this->configuration[$layer])) {
  10373.             return false;
  10374.         }
  10375.         if ($key == 'default_channel') {
  10376.             // can only set this value globally
  10377.             $channel = 'pear.php.net';
  10378.             if ($value != 'pear.php.net') {
  10379.                 $this->_lazyChannelSetup($layer);
  10380.             }
  10381.         }
  10382.         if ($key == 'preferred_mirror') {
  10383.             if ($channel == '__uri') {
  10384.                 return false; // can't set the __uri pseudo-channel's mirror
  10385.             }
  10386.             $reg = &$this->getRegistry($layer);
  10387.             if (is_object($reg)) {
  10388.                 $chan = &$reg->getChannel($channel ? $channel : 'pear.php.net');
  10389.                 if (PEAR::isError($chan)) {
  10390.                     return false;
  10391.                 }
  10392.                 if (!$chan->getMirror($value) && $chan->getName() != $value) {
  10393.                     return false; // mirror does not exist
  10394.                 }
  10395.             }
  10396.         }
  10397.         if (empty($this->configuration_info[$key])) {
  10398.             return false;
  10399.         }
  10400.         extract($this->configuration_info[$key]);
  10401.         switch ($type) {
  10402.             case 'integer':
  10403.                 $value = (int)$value;
  10404.                 break;
  10405.             case 'set': {
  10406.                 // If a valid_set is specified, require the value to
  10407.                 // be in the set.  If there is no valid_set, accept
  10408.                 // any value.
  10409.                 if ($valid_set) {
  10410.                     reset($valid_set);
  10411.                     if ((key($valid_set) === 0 && !in_array($value, $valid_set)) ||
  10412.                         (key($valid_set) !== 0 && empty($valid_set[$value])))
  10413.                     {
  10414.                         return false;
  10415.                     }
  10416.                 }
  10417.                 break;
  10418.             }
  10419.         }
  10420.         if (!$channel) {
  10421.             $channel = $this->get('default_channel', null, 'pear.php.net');
  10422.         }
  10423.         if (!in_array($channel, $this->_channels)) {
  10424.             $this->_lazyChannelSetup($layer);
  10425.             $reg = &$this->getRegistry($layer);
  10426.             if ($reg) {
  10427.                 $channel = $reg->channelName($channel);
  10428.             }
  10429.             if (!in_array($channel, $this->_channels)) {
  10430.                 return false;
  10431.             }
  10432.         }
  10433.         if ($channel != 'pear.php.net') {
  10434.             if (in_array($key, $this->_channelConfigInfo)) {
  10435.                 $this->configuration[$layer]['__channels'][$channel][$key] = $value;
  10436.                 return true;
  10437.             } else {
  10438.                 return false;
  10439.             }
  10440.         } else {
  10441.             if ($key == 'default_channel') {
  10442.                 if (!isset($reg)) {
  10443.                     $reg = &$this->getRegistry($layer);
  10444.                     if (!$reg) {
  10445.                         $reg = &$this->getRegistry();
  10446.                     }
  10447.                 }
  10448.                 if ($reg) {
  10449.                     $value = $reg->channelName($value);
  10450.                 }
  10451.                 if (!$value) {
  10452.                     return false;
  10453.                 }
  10454.             }
  10455.         }
  10456.         $this->configuration[$layer][$key] = $value;
  10457.         if ($key == 'php_dir' && !$this->_noRegistry) {
  10458.             if (!isset($this->_registry[$layer]) ||
  10459.                   $value != $this->_registry[$layer]->install_dir) {
  10460.                 $this->_registry[$layer] = &new PEAR_Registry($value);
  10461.                 $this->_regInitialized[$layer] = false;
  10462.                 $this->_registry[$layer]->setConfig($this);
  10463.             }
  10464.         }
  10465.         return true;
  10466.     }
  10467.  
  10468.     // }}}
  10469.     function _lazyChannelSetup($uselayer = false)
  10470.     {
  10471.         if ($this->_noRegistry) {
  10472.             return;
  10473.         }
  10474.         $merge = false;
  10475.         foreach ($this->_registry as $layer => $p) {
  10476.             if ($uselayer && $uselayer != $layer) {
  10477.                 continue;
  10478.             }
  10479.             if (!$this->_regInitialized[$layer]) {
  10480.                 if ($layer == 'default' && isset($this->_registry['user']) ||
  10481.                       isset($this->_registry['system'])) {
  10482.                     // only use the default registry if there are no alternatives
  10483.                     continue;
  10484.                 }
  10485.                 if (!is_object($this->_registry[$layer])) {
  10486.                     if ($phpdir = $this->get('php_dir', $layer, 'pear.php.net')) {
  10487.                         $this->_registry[$layer] = &new PEAR_Registry($phpdir);
  10488.                         $this->_registry[$layer]->setConfig($this);
  10489.                         $this->_regInitialized[$layer] = false;
  10490.                     } else {
  10491.                         unset($this->_registry[$layer]);
  10492.                         return;
  10493.                     }
  10494.                 }
  10495.                 $this->setChannels($this->_registry[$layer]->listChannels(), $merge);
  10496.                 $this->_regInitialized[$layer] = true;
  10497.                 $merge = true;
  10498.             }
  10499.         }
  10500.     }
  10501.     // {{{ setChannels()
  10502.     
  10503.     /**
  10504.      * Set the list of channels.
  10505.      *
  10506.      * This should be set via a call to {@link PEAR_Registry::listChannels()}
  10507.      * @param array
  10508.      * @param bool
  10509.      * @return bool success of operation
  10510.      */
  10511.     function setChannels($channels, $merge = false)
  10512.     {
  10513.         if (!is_array($channels)) {
  10514.             return false;
  10515.         }
  10516.         if ($merge) {
  10517.             $this->_channels = array_merge($this->_channels, $channels);
  10518.         } else {
  10519.             $this->_channels = $channels;
  10520.         }
  10521.         foreach ($channels as $channel) {
  10522.             $channel = strtolower($channel);
  10523.             if ($channel == 'pear.php.net') {
  10524.                 continue;
  10525.             }
  10526.             foreach ($this->layers as $layer) {
  10527.                 if (!isset($this->configuration[$layer]['__channels'])) {
  10528.                     $this->configuration[$layer]['__channels'] = array();
  10529.                 }
  10530.                 if (!isset($this->configuration[$layer]['__channels'][$channel])
  10531.                       || !is_array($this->configuration[$layer]['__channels'][$channel])) {
  10532.                     $this->configuration[$layer]['__channels'][$channel] = array();
  10533.                 }
  10534.             }
  10535.         }
  10536.         return true;
  10537.     }
  10538.  
  10539.     // }}}
  10540.     // {{{ getType(key)
  10541.  
  10542.     /**
  10543.      * Get the type of a config value.
  10544.      *
  10545.      * @param string  config key
  10546.      *
  10547.      * @return string type, one of "string", "integer", "file",
  10548.      * "directory", "set" or "password".
  10549.      *
  10550.      * @access public
  10551.      *
  10552.      */
  10553.     function getType($key)
  10554.     {
  10555.         if (isset($this->configuration_info[$key])) {
  10556.             return $this->configuration_info[$key]['type'];
  10557.         }
  10558.         return false;
  10559.     }
  10560.  
  10561.     // }}}
  10562.     // {{{ getDocs(key)
  10563.  
  10564.     /**
  10565.      * Get the documentation for a config value.
  10566.      *
  10567.      * @param string  config key
  10568.      *
  10569.      * @return string documentation string
  10570.      *
  10571.      * @access public
  10572.      *
  10573.      */
  10574.     function getDocs($key)
  10575.     {
  10576.         if (isset($this->configuration_info[$key])) {
  10577.             return $this->configuration_info[$key]['doc'];
  10578.         }
  10579.         return false;
  10580.     }
  10581.        // }}}
  10582.     // {{{ getPrompt(key)
  10583.  
  10584.     /**
  10585.      * Get the short documentation for a config value.
  10586.      *
  10587.      * @param string  config key
  10588.      *
  10589.      * @return string short documentation string
  10590.      *
  10591.      * @access public
  10592.      *
  10593.      */
  10594.     function getPrompt($key)
  10595.     {
  10596.         if (isset($this->configuration_info[$key])) {
  10597.             return $this->configuration_info[$key]['prompt'];
  10598.         }
  10599.         return false;
  10600.     }
  10601.     // }}}
  10602.     // {{{ getGroup(key)
  10603.  
  10604.     /**
  10605.      * Get the parameter group for a config key.
  10606.      *
  10607.      * @param string  config key
  10608.      *
  10609.      * @return string parameter group
  10610.      *
  10611.      * @access public
  10612.      *
  10613.      */
  10614.     function getGroup($key)
  10615.     {
  10616.         if (isset($this->configuration_info[$key])) {
  10617.             return $this->configuration_info[$key]['group'];
  10618.         }
  10619.         return false;
  10620.     }
  10621.  
  10622.     // }}}
  10623.     // {{{ getGroups()
  10624.  
  10625.     /**
  10626.      * Get the list of parameter groups.
  10627.      *
  10628.      * @return array list of parameter groups
  10629.      *
  10630.      * @access public
  10631.      *
  10632.      */
  10633.     function getGroups()
  10634.     {
  10635.         $tmp = array();
  10636.         foreach ($this->configuration_info as $key => $info) {
  10637.             $tmp[$info['group']] = 1;
  10638.         }
  10639.         return array_keys($tmp);
  10640.     }
  10641.  
  10642.     // }}}
  10643.     // {{{ getGroupKeys()
  10644.  
  10645.     /**
  10646.      * Get the list of the parameters in a group.
  10647.      *
  10648.      * @param string $group parameter group
  10649.      *
  10650.      * @return array list of parameters in $group
  10651.      *
  10652.      * @access public
  10653.      *
  10654.      */
  10655.     function getGroupKeys($group)
  10656.     {
  10657.         $keys = array();
  10658.         foreach ($this->configuration_info as $key => $info) {
  10659.             if ($info['group'] == $group) {
  10660.                 $keys[] = $key;
  10661.             }
  10662.         }
  10663.         return $keys;
  10664.     }
  10665.  
  10666.     // }}}
  10667.     // {{{ getSetValues(key)
  10668.  
  10669.     /**
  10670.      * Get the list of allowed set values for a config value.  Returns
  10671.      * NULL for config values that are not sets.
  10672.      *
  10673.      * @param string  config key
  10674.      *
  10675.      * @return array enumerated array of set values, or NULL if the
  10676.      *               config key is unknown or not a set
  10677.      *
  10678.      * @access public
  10679.      *
  10680.      */
  10681.     function getSetValues($key)
  10682.     {
  10683.         if (isset($this->configuration_info[$key]) &&
  10684.             isset($this->configuration_info[$key]['type']) &&
  10685.             $this->configuration_info[$key]['type'] == 'set')
  10686.         {
  10687.             $valid_set = $this->configuration_info[$key]['valid_set'];
  10688.             reset($valid_set);
  10689.             if (key($valid_set) === 0) {
  10690.                 return $valid_set;
  10691.             }
  10692.             return array_keys($valid_set);
  10693.         }
  10694.         return null;
  10695.     }
  10696.  
  10697.     // }}}
  10698.     // {{{ getKeys()
  10699.  
  10700.     /**
  10701.      * Get all the current config keys.
  10702.      *
  10703.      * @return array simple array of config keys
  10704.      *
  10705.      * @access public
  10706.      */
  10707.     function getKeys()
  10708.     {
  10709.         $keys = array();
  10710.         foreach ($this->layers as $layer) {
  10711.             $test = $this->configuration[$layer];
  10712.             if (isset($test['__channels'])) {
  10713.                 foreach ($test['__channels'] as $channel => $configs) {
  10714.                     $keys = array_merge($keys, $configs);
  10715.                 }
  10716.             }
  10717.             unset($test['__channels']);
  10718.             $keys = array_merge($keys, $test);
  10719.         }
  10720.         return array_keys($keys);
  10721.     }
  10722.  
  10723.     // }}}
  10724.     // {{{ remove(key, [layer])
  10725.  
  10726.     /**
  10727.      * Remove the a config key from a specific config layer.
  10728.      *
  10729.      * @param string config key
  10730.      *
  10731.      * @param string (optional) config layer
  10732.      *
  10733.      * @return bool TRUE on success, FALSE on failure
  10734.      *
  10735.      * @access public
  10736.      */
  10737.     function remove($key, $layer = 'user')
  10738.     {
  10739.         $channel = $this->getDefaultChannel();
  10740.         if ($channel !== 'pear.php.net') {
  10741.             if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  10742.                 unset($this->configuration[$layer]['__channels'][$channel][$key]);
  10743.                 return true;
  10744.             }
  10745.         }
  10746.         if (isset($this->configuration[$layer][$key])) {
  10747.             unset($this->configuration[$layer][$key]);
  10748.             return true;
  10749.         }
  10750.         return false;
  10751.     }
  10752.  
  10753.     // }}}
  10754.     // {{{ removeLayer(layer)
  10755.  
  10756.     /**
  10757.      * Temporarily remove an entire config layer.  USE WITH CARE!
  10758.      *
  10759.      * @param string config key
  10760.      *
  10761.      * @param string (optional) config layer
  10762.      *
  10763.      * @return bool TRUE on success, FALSE on failure
  10764.      *
  10765.      * @access public
  10766.      */
  10767.     function removeLayer($layer)
  10768.     {
  10769.         if (isset($this->configuration[$layer])) {
  10770.             $this->configuration[$layer] = array();
  10771.             return true;
  10772.         }
  10773.         return false;
  10774.     }
  10775.  
  10776.     // }}}
  10777.     // {{{ store([layer])
  10778.  
  10779.     /**
  10780.      * Stores configuration data in a layer.
  10781.      *
  10782.      * @param string config layer to store
  10783.      *
  10784.      * @return bool TRUE on success, or PEAR error on failure
  10785.      *
  10786.      * @access public
  10787.      */
  10788.     function store($layer = 'user', $data = null)
  10789.     {
  10790.         return $this->writeConfigFile(null, $layer, $data);
  10791.     }
  10792.  
  10793.     // }}}
  10794.     // {{{ toDefault(key)
  10795.  
  10796.     /**
  10797.      * Unset the user-defined value of a config key, reverting the
  10798.      * value to the system-defined one.
  10799.      *
  10800.      * @param string config key
  10801.      *
  10802.      * @return bool TRUE on success, FALSE on failure
  10803.      *
  10804.      * @access public
  10805.      */
  10806.     function toDefault($key)
  10807.     {
  10808.         trigger_error("PEAR_Config::toDefault() deprecated, use PEAR_Config::remove() instead", E_USER_NOTICE);
  10809.         return $this->remove($key, 'user');
  10810.     }
  10811.  
  10812.     // }}}
  10813.     // {{{ definedBy(key)
  10814.  
  10815.     /**
  10816.      * Tells what config layer that gets to define a key.
  10817.      *
  10818.      * @param string config key
  10819.      * @param boolean return the defining channel
  10820.      *
  10821.      * @return string|array the config layer, or an empty string if not found.
  10822.      *
  10823.      *         if $returnchannel, the return is an array array('layer' => layername,
  10824.      *         'channel' => channelname), or an empty string if not found
  10825.      *
  10826.      * @access public
  10827.      */
  10828.     function definedBy($key, $returnchannel = false)
  10829.     {
  10830.         foreach ($this->layers as $layer) {
  10831.             $channel = $this->getDefaultChannel();
  10832.             if ($channel !== 'pear.php.net') {
  10833.                 if (isset($this->configuration[$layer]['__channels'][$channel][$key])) {
  10834.                     if ($returnchannel) {
  10835.                         return array('layer' => $layer, 'channel' => $channel);
  10836.                     }
  10837.                     return $layer;
  10838.                 }
  10839.             }
  10840.             if (isset($this->configuration[$layer][$key])) {
  10841.                 if ($returnchannel) {
  10842.                     return array('layer' => $layer, 'channel' => 'pear.php.net');
  10843.                 }
  10844.                 return $layer;
  10845.             }
  10846.         }
  10847.         return '';
  10848.     }
  10849.  
  10850.     // }}}
  10851.     // {{{ isDefaulted(key)
  10852.  
  10853.     /**
  10854.      * Tells whether a config value has a system-defined value.
  10855.      *
  10856.      * @param string   config key
  10857.      *
  10858.      * @return bool
  10859.      *
  10860.      * @access public
  10861.      *
  10862.      * @deprecated
  10863.      */
  10864.     function isDefaulted($key)
  10865.     {
  10866.         trigger_error("PEAR_Config::isDefaulted() deprecated, use PEAR_Config::definedBy() instead", E_USER_NOTICE);
  10867.         return $this->definedBy($key) == 'system';
  10868.     }
  10869.  
  10870.     // }}}
  10871.     // {{{ isDefined(key)
  10872.  
  10873.     /**
  10874.      * Tells whether a given key exists as a config value.
  10875.      *
  10876.      * @param string config key
  10877.      *
  10878.      * @return bool whether <config key> exists in this object
  10879.      *
  10880.      * @access public
  10881.      */
  10882.     function isDefined($key)
  10883.     {
  10884.         foreach ($this->layers as $layer) {
  10885.             if (isset($this->configuration[$layer][$key])) {
  10886.                 return true;
  10887.             }
  10888.         }
  10889.         return false;
  10890.     }
  10891.  
  10892.     // }}}
  10893.     // {{{ isDefinedLayer(key)
  10894.  
  10895.     /**
  10896.      * Tells whether a given config layer exists.
  10897.      *
  10898.      * @param string config layer
  10899.      *
  10900.      * @return bool whether <config layer> exists in this object
  10901.      *
  10902.      * @access public
  10903.      */
  10904.     function isDefinedLayer($layer)
  10905.     {
  10906.         return isset($this->configuration[$layer]);
  10907.     }
  10908.  
  10909.     // }}}
  10910.     // {{{ getLayers()
  10911.  
  10912.     /**
  10913.      * Returns the layers defined (except the 'default' one)
  10914.      *
  10915.      * @return array of the defined layers
  10916.      */
  10917.     function getLayers()
  10918.     {
  10919.         $cf = $this->configuration;
  10920.         unset($cf['default']);
  10921.         return array_keys($cf);
  10922.     }
  10923.  
  10924.     // }}}
  10925.     // {{{ apiVersion()
  10926.     function apiVersion()
  10927.     {
  10928.         return '1.1';
  10929.     }
  10930.     // }}}
  10931.  
  10932.     /**
  10933.      * @return PEAR_Registry
  10934.      */
  10935.     function &getRegistry($use = null)
  10936.     {
  10937.         if ($use === null) {
  10938.             $layer = 'user';
  10939.         } else {
  10940.             $layer = $use;
  10941.         }
  10942.         if (isset($this->_registry[$layer])) {
  10943.             return $this->_registry[$layer];
  10944.         } elseif ($use === null && isset($this->_registry['system'])) {
  10945.             return $this->_registry['system'];
  10946.         } elseif ($use === null && isset($this->_registry['default'])) {
  10947.             return $this->_registry['default'];
  10948.         } elseif ($use) {
  10949.             $a = false;
  10950.             return $a;
  10951.         } else {
  10952.             // only go here if null was passed in
  10953.             echo "CRITICAL ERROR: Registry could not be initialized from any value";
  10954.             exit(1);
  10955.         }
  10956.     }
  10957.     /**
  10958.      * This is to allow customization like the use of installroot
  10959.      * @param PEAR_Registry
  10960.      * @return bool
  10961.      */
  10962.     function setRegistry(&$reg, $layer = 'user')
  10963.     {
  10964.         if ($this->_noRegistry) {
  10965.             return false;
  10966.         }
  10967.         if (!in_array($layer, array('user', 'system'))) {
  10968.             return false;
  10969.         }
  10970.         $this->_registry[$layer] = &$reg;
  10971.         if (is_object($reg)) {
  10972.             $this->_registry[$layer]->setConfig($this);
  10973.         }
  10974.         return true;
  10975.     }
  10976.  
  10977.     function noRegistry()
  10978.     {
  10979.         $this->_noRegistry = true;
  10980.     }
  10981.  
  10982.     /**
  10983.      * @return PEAR_Remote
  10984.      */
  10985.     function &getRemote()
  10986.     {
  10987.         $remote = &new PEAR_Remote($this);
  10988.         return $remote;
  10989.     }
  10990.  
  10991.     /**
  10992.      * @return PEAR_REST
  10993.      */
  10994.     function &getREST($version, $options = array())
  10995.     {
  10996.         $version = str_replace('.', '', $version);
  10997.         if (!class_exists($class = 'PEAR_REST_' . $version)) {
  10998.             require_once 'phar://go-pear.phar/PEAR/REST/' . $version . '.php';
  10999.         }
  11000.         $remote = &new $class($this, $options);
  11001.         return $remote;
  11002.     }
  11003.  
  11004.     /**
  11005.      * The ftp server is set in {@link readFTPConfigFile()}.  It exists only if a
  11006.      * remote configuration file has been specified
  11007.      * @return PEAR_FTP|false
  11008.      */
  11009.     function &getFTP()
  11010.     {
  11011.         if (isset($this->_ftp)) {
  11012.             return $this->_ftp;
  11013.         } else {
  11014.             $a = false;
  11015.             return $a;
  11016.         }
  11017.     }
  11018.  
  11019.     // {{{ _prependPath($path, $prepend)
  11020.  
  11021.     function _prependPath($path, $prepend)
  11022.     {
  11023.         if (strlen($prepend) > 0) {
  11024.             if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
  11025.                 if (preg_match('/^[a-z]:/i', $prepend)) {
  11026.                     $prepend = substr($prepend, 2);
  11027.                 } elseif ($prepend{0} != '\\') {
  11028.                     $prepend = "\\$prepend";
  11029.                 }
  11030.                 $path = substr($path, 0, 2) . $prepend . substr($path, 2);
  11031.             } else {
  11032.                 $path = $prepend . $path;
  11033.             }
  11034.         }
  11035.         return $path;
  11036.     }
  11037.     // }}}
  11038.  
  11039.     /**
  11040.      * @param string|false installation directory to prepend to all _dir variables, or false to
  11041.      *                     disable
  11042.      */
  11043.     function setInstallRoot($root)
  11044.     {
  11045.         if (substr($root, -1) == DIRECTORY_SEPARATOR) {
  11046.             $root = substr($root, 0, -1);
  11047.         }
  11048.         $old = $this->_installRoot;
  11049.         $this->_installRoot = $root;
  11050.         if (($old != $root) && !$this->_noRegistry) {
  11051.             foreach (array_keys($this->_registry) as $layer) {
  11052.                 if ($layer == 'ftp' || !isset($this->_registry[$layer])) {
  11053.                     continue;
  11054.                 }
  11055.                 $this->_registry[$layer] =
  11056.                     &new PEAR_Registry($this->get('php_dir', $layer, 'pear.php.net'));
  11057.                 $this->_registry[$layer]->setConfig($this);
  11058.                 $this->_regInitialized[$layer] = false;
  11059.             }
  11060.         }
  11061.     }
  11062. }
  11063.  
  11064. ?>
  11065. <?php
  11066. /**
  11067.  * PEAR_Dependency2, advanced dependency validation
  11068.  *
  11069.  * PHP versions 4 and 5
  11070.  *
  11071.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  11072.  * that is available through the world-wide-web at the following URI:
  11073.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  11074.  * the PHP License and are unable to obtain it through the web, please
  11075.  * send a note to license@php.net so we can mail you a copy immediately.
  11076.  *
  11077.  * @category   pear
  11078.  * @package    PEAR
  11079.  * @author     Greg Beaver <cellog@php.net>
  11080.  * @copyright  1997-2006 The PHP Group
  11081.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  11082.  * @version    CVS: $Id: Dependency2.php,v 1.51 2006/09/19 04:29:43 cellog Exp $
  11083.  * @link       http://pear.php.net/package/PEAR
  11084.  * @since      File available since Release 1.4.0a1
  11085.  */
  11086.  
  11087. /**
  11088.  * Required for the PEAR_VALIDATE_* constants
  11089.  */
  11090. require_once 'phar://go-pear.phar/PEAR/Validate.php';
  11091.  
  11092. /**
  11093.  * Dependency check for PEAR packages
  11094.  *
  11095.  * This class handles both version 1.0 and 2.0 dependencies
  11096.  * WARNING: *any* changes to this class must be duplicated in the
  11097.  * test_PEAR_Dependency2 class found in tests/PEAR_Dependency2/setup.php.inc,
  11098.  * or unit tests will not actually validate the changes
  11099.  * @category   pear
  11100.  * @package    PEAR
  11101.  * @author     Greg Beaver <cellog@php.net>
  11102.  * @copyright  1997-2006 The PHP Group
  11103.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  11104.  * @version    Release: 1.5.0a2
  11105.  * @link       http://pear.php.net/package/PEAR
  11106.  * @since      Class available since Release 1.4.0a1
  11107.  */
  11108. class PEAR_Dependency2
  11109. {
  11110.     /**
  11111.      * One of the PEAR_VALIDATE_* states
  11112.      * @see PEAR_VALIDATE_NORMAL
  11113.      * @var integer
  11114.      */
  11115.     var $_state;
  11116.     /**
  11117.      * Command-line options to install/upgrade/uninstall commands
  11118.      * @param array
  11119.      */
  11120.     var $_options;
  11121.     /**
  11122.      * @var OS_Guess
  11123.      */
  11124.     var $_os;
  11125.     /**
  11126.      * @var PEAR_Registry
  11127.      */
  11128.     var $_registry;
  11129.     /**
  11130.      * @var PEAR_Config
  11131.      */
  11132.     var $_config;
  11133.     /**
  11134.      * @var PEAR_DependencyDB
  11135.      */
  11136.     var $_dependencydb;
  11137.     /**
  11138.      * Output of PEAR_Registry::parsedPackageName()
  11139.      * @var array
  11140.      */
  11141.     var $_currentPackage;
  11142.     /**
  11143.      * @param PEAR_Config
  11144.      * @param array installation options
  11145.      * @param array format of PEAR_Registry::parsedPackageName()
  11146.      * @param int installation state (one of PEAR_VALIDATE_*)
  11147.      */
  11148.     function PEAR_Dependency2(&$config, $installoptions, $package,
  11149.                               $state = PEAR_VALIDATE_INSTALLING)
  11150.     {
  11151.         $this->_config = &$config;
  11152.         if (!class_exists('PEAR_DependencyDB')) {
  11153.             require_once 'phar://go-pear.phar/PEAR/DependencyDB.php';
  11154.         }
  11155.         if (isset($installoptions['packagingroot'])) {
  11156.             // make sure depdb is in the right location
  11157.             $config->setInstallRoot($installoptions['packagingroot']);
  11158.         }
  11159.         $this->_registry = &$config->getRegistry();
  11160.         $this->_dependencydb = &PEAR_DependencyDB::singleton($config);
  11161.         if (isset($installoptions['packagingroot'])) {
  11162.             $config->setInstallRoot(false);
  11163.         }
  11164.         $this->_options = $installoptions;
  11165.         $this->_state = $state;
  11166.         if (!class_exists('OS_Guess')) {
  11167.             require_once 'phar://go-pear.phar/OS/Guess.php';
  11168.         }
  11169.         $this->_os = new OS_Guess;
  11170.         $this->_currentPackage = $package;
  11171.     }
  11172.  
  11173.     function _getExtraString($dep)
  11174.     {
  11175.         $extra = ' (';
  11176.         if (isset($dep['uri'])) {
  11177.             return '';
  11178.         }
  11179.         if (isset($dep['recommended'])) {
  11180.             $extra .= 'recommended version ' . $dep['recommended'];
  11181.         } else {
  11182.             if (isset($dep['min'])) {
  11183.                 $extra .= 'version >= ' . $dep['min'];
  11184.             }
  11185.             if (isset($dep['max'])) {
  11186.                 if ($extra != ' (') {
  11187.                     $extra .= ', ';
  11188.                 }
  11189.                 $extra .= 'version <= ' . $dep['max'];
  11190.             }
  11191.             if (isset($dep['exclude'])) {
  11192.                 if (!is_array($dep['exclude'])) {
  11193.                     $dep['exclude'] = array($dep['exclude']);
  11194.                 }
  11195.                 if ($extra != ' (') {
  11196.                     $extra .= ', ';
  11197.                 }
  11198.                 $extra .= 'excluded versions: ';
  11199.                 foreach ($dep['exclude'] as $i => $exclude) {
  11200.                     if ($i) {
  11201.                         $extra .= ', ';
  11202.                     }
  11203.                     $extra .= $exclude;
  11204.                 }
  11205.             }
  11206.         }
  11207.         $extra .= ')';
  11208.         if ($extra == ' ()') {
  11209.             $extra = '';
  11210.         }
  11211.         return $extra;
  11212.     }
  11213.  
  11214.     /**
  11215.      * This makes unit-testing a heck of a lot easier
  11216.      */
  11217.     function getPHP_OS()
  11218.     {
  11219.         return PHP_OS;
  11220.     }
  11221.  
  11222.     /**
  11223.      * This makes unit-testing a heck of a lot easier
  11224.      */
  11225.     function getsysname()
  11226.     {
  11227.         return $this->_os->getSysname();
  11228.     }
  11229.  
  11230.     /**
  11231.      * Specify a dependency on an OS.  Use arch for detailed os/processor information
  11232.      *
  11233.      * There are two generic OS dependencies that will be the most common, unix and windows.
  11234.      * Other options are linux, freebsd, darwin (OS X), sunos, irix, hpux, aix
  11235.      */
  11236.     function validateOsDependency($dep)
  11237.     {
  11238.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  11239.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  11240.             return true;
  11241.         }
  11242.         if (isset($dep['conflicts'])) {
  11243.             $not = true;
  11244.         } else {
  11245.             $not = false;
  11246.         }
  11247.         if ($dep['name'] == '*') {
  11248.             return true;
  11249.         }
  11250.         switch (strtolower($dep['name'])) {
  11251.             case 'windows' :
  11252.                 if ($not) {
  11253.                     if (strtolower(substr($this->getPHP_OS(), 0, 3)) == 'win') {
  11254.                         if (!isset($this->_options['nodeps']) &&
  11255.                               !isset($this->_options['force'])) {
  11256.                             return $this->raiseError("Cannot install %s on Windows");
  11257.                         } else {
  11258.                             return $this->warning("warning: Cannot install %s on Windows");
  11259.                         }
  11260.                     }
  11261.                 } else {
  11262.                     if (strtolower(substr($this->getPHP_OS(), 0, 3)) != 'win') {
  11263.                         if (!isset($this->_options['nodeps']) &&
  11264.                               !isset($this->_options['force'])) {
  11265.                             return $this->raiseError("Can only install %s on Windows");
  11266.                         } else {
  11267.                             return $this->warning("warning: Can only install %s on Windows");
  11268.                         }
  11269.                     }
  11270.                 }
  11271.             break;
  11272.             case 'unix' :
  11273.                 $unices = array('linux', 'freebsd', 'darwin', 'sunos', 'irix', 'hpux', 'aix');
  11274.                 if ($not) {
  11275.                     if (in_array($this->getSysname(), $unices)) {
  11276.                         if (!isset($this->_options['nodeps']) &&
  11277.                               !isset($this->_options['force'])) {
  11278.                             return $this->raiseError("Cannot install %s on any Unix system");
  11279.                         } else {
  11280.                             return $this->warning(
  11281.                                 "warning: Cannot install %s on any Unix system");
  11282.                         }
  11283.                     }
  11284.                 } else {
  11285.                     if (!in_array($this->getSysname(), $unices)) {
  11286.                         if (!isset($this->_options['nodeps']) &&
  11287.                               !isset($this->_options['force'])) {
  11288.                             return $this->raiseError("Can only install %s on a Unix system");
  11289.                         } else {
  11290.                             return $this->warning(
  11291.                                 "warning: Can only install %s on a Unix system");
  11292.                         }
  11293.                     }
  11294.                 }
  11295.             break;
  11296.             default :
  11297.                 if ($not) {
  11298.                     if (strtolower($dep['name']) == strtolower($this->getSysname())) {
  11299.                         if (!isset($this->_options['nodeps']) &&
  11300.                               !isset($this->_options['force'])) {
  11301.                             return $this->raiseError('Cannot install %s on ' . $dep['name'] .
  11302.                                 ' operating system');
  11303.                         } else {
  11304.                             return $this->warning('warning: Cannot install %s on ' .
  11305.                                 $dep['name'] . ' operating system');
  11306.                         }
  11307.                     }
  11308.                 } else {
  11309.                     if (strtolower($dep['name']) != strtolower($this->getSysname())) {
  11310.                         if (!isset($this->_options['nodeps']) &&
  11311.                               !isset($this->_options['force'])) {
  11312.                             return $this->raiseError('Cannot install %s on ' .
  11313.                                 $this->getSysname() .
  11314.                                 ' operating system, can only install on ' . $dep['name']);
  11315.                         } else {
  11316.                             return $this->warning('warning: Cannot install %s on ' .
  11317.                                 $this->getSysname() .
  11318.                                 ' operating system, can only install on ' . $dep['name']);
  11319.                         }
  11320.                     }
  11321.                 }
  11322.         }
  11323.         return true;
  11324.     }
  11325.  
  11326.     /**
  11327.      * This makes unit-testing a heck of a lot easier
  11328.      */
  11329.     function matchSignature($pattern)
  11330.     {
  11331.         return $this->_os->matchSignature($pattern);
  11332.     }
  11333.  
  11334.     /**
  11335.      * Specify a complex dependency on an OS/processor/kernel version,
  11336.      * Use OS for simple operating system dependency.
  11337.      *
  11338.      * This is the only dependency that accepts an eregable pattern.  The pattern
  11339.      * will be matched against the php_uname() output parsed by OS_Guess
  11340.      */
  11341.     function validateArchDependency($dep)
  11342.     {
  11343.         if ($this->_state != PEAR_VALIDATE_INSTALLING) {
  11344.             return true;
  11345.         }
  11346.         if (isset($dep['conflicts'])) {
  11347.             $not = true;
  11348.         } else {
  11349.             $not = false;
  11350.         }
  11351.         if (!$this->matchSignature($dep['pattern'])) {
  11352.             if (!$not) {
  11353.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11354.                     return $this->raiseError('%s Architecture dependency failed, does not ' .
  11355.                         'match "' . $dep['pattern'] . '"');
  11356.                 } else {
  11357.                     return $this->warning('warning: %s Architecture dependency failed, does ' .
  11358.                         'not match "' . $dep['pattern'] . '"');
  11359.                 }
  11360.             }
  11361.             return true;
  11362.         } else {
  11363.             if ($not) {
  11364.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11365.                     return $this->raiseError('%s Architecture dependency failed, required "' .
  11366.                         $dep['pattern'] . '"');
  11367.                 } else {
  11368.                     return $this->warning('warning: %s Architecture dependency failed, ' .
  11369.                         'required "' . $dep['pattern'] . '"');
  11370.                 }
  11371.             }
  11372.             return true;
  11373.         }
  11374.     }
  11375.  
  11376.     /**
  11377.      * This makes unit-testing a heck of a lot easier
  11378.      */
  11379.     function extension_loaded($name)
  11380.     {
  11381.         return extension_loaded($name);
  11382.     }
  11383.  
  11384.     /**
  11385.      * This makes unit-testing a heck of a lot easier
  11386.      */
  11387.     function phpversion($name = null)
  11388.     {
  11389.         if ($name !== null) {
  11390.             return phpversion($name);
  11391.         } else {
  11392.             return phpversion();
  11393.         }
  11394.     }
  11395.  
  11396.     function validateExtensionDependency($dep, $required = true)
  11397.     {
  11398.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  11399.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  11400.             return true;
  11401.         }
  11402.         $loaded = $this->extension_loaded($dep['name']);
  11403.         $extra = $this->_getExtraString($dep);
  11404.         if (isset($dep['exclude'])) {
  11405.             if (!is_array($dep['exclude'])) {
  11406.                 $dep['exclude'] = array($dep['exclude']);
  11407.             }
  11408.         }
  11409.         if (!isset($dep['min']) && !isset($dep['max']) &&
  11410.               !isset($dep['recommended']) && !isset($dep['exclude'])) {
  11411.             if ($loaded) {
  11412.                 if (isset($dep['conflicts'])) {
  11413.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11414.                         return $this->raiseError('%s conflicts with PHP extension "' .
  11415.                             $dep['name'] . '"' . $extra);
  11416.                     } else {
  11417.                         return $this->warning('warning: %s conflicts with PHP extension "' .
  11418.                             $dep['name'] . '"' . $extra);
  11419.                     }
  11420.                 }
  11421.                 return true;
  11422.             } else {
  11423.                 if (isset($dep['conflicts'])) {
  11424.                     return true;
  11425.                 }
  11426.                 if ($required) {
  11427.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11428.                         return $this->raiseError('%s requires PHP extension "' .
  11429.                             $dep['name'] . '"' . $extra);
  11430.                     } else {
  11431.                         return $this->warning('warning: %s requires PHP extension "' .
  11432.                             $dep['name'] . '"' . $extra);
  11433.                     }
  11434.                 } else {
  11435.                     return $this->warning('%s can optionally use PHP extension "' .
  11436.                         $dep['name'] . '"' . $extra);
  11437.                 }
  11438.             }
  11439.         }
  11440.         if (!$loaded) {
  11441.             if (isset($dep['conflicts'])) {
  11442.                 return true;
  11443.             }
  11444.             if (!$required) {
  11445.                 return $this->warning('%s can optionally use PHP extension "' .
  11446.                     $dep['name'] . '"' . $extra);
  11447.             } else {
  11448.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11449.                     return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  11450.                         '"' . $extra);
  11451.                 }
  11452.                     return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  11453.                         '"' . $extra);
  11454.             }
  11455.         }
  11456.         $version = (string) $this->phpversion($dep['name']);
  11457.         if (empty($version)) {
  11458.             $version = '0';
  11459.         }
  11460.         $fail = false;
  11461.         if (isset($dep['min'])) {
  11462.             if (!version_compare($version, $dep['min'], '>=')) {
  11463.                 $fail = true;
  11464.             }
  11465.         }
  11466.         if (isset($dep['max'])) {
  11467.             if (!version_compare($version, $dep['max'], '<=')) {
  11468.                 $fail = true;
  11469.             }
  11470.         }
  11471.         if ($fail && !isset($dep['conflicts'])) {
  11472.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11473.                 return $this->raiseError('%s requires PHP extension "' . $dep['name'] .
  11474.                     '"' . $extra . ', installed version is ' . $version);
  11475.             } else {
  11476.                 return $this->warning('warning: %s requires PHP extension "' . $dep['name'] .
  11477.                     '"' . $extra . ', installed version is ' . $version);
  11478.             }
  11479.         } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail && isset($dep['conflicts'])) {
  11480.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11481.                 return $this->raiseError('%s conflicts with PHP extension "' .
  11482.                     $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  11483.             } else {
  11484.                 return $this->warning('warning: %s conflicts with PHP extension "' .
  11485.                     $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  11486.             }
  11487.         }
  11488.         if (isset($dep['exclude'])) {
  11489.             foreach ($dep['exclude'] as $exclude) {
  11490.                 if (version_compare($version, $exclude, '==')) {
  11491.                     if (isset($dep['conflicts'])) {
  11492.                         continue;
  11493.                     }
  11494.                     if (!isset($this->_options['nodeps']) &&
  11495.                           !isset($this->_options['force'])) {
  11496.                         return $this->raiseError('%s is not compatible with PHP extension "' .
  11497.                             $dep['name'] . '" version ' .
  11498.                             $exclude);
  11499.                     } else {
  11500.                         return $this->warning('warning: %s is not compatible with PHP extension "' .
  11501.                             $dep['name'] . '" version ' .
  11502.                             $exclude);
  11503.                     }
  11504.                 } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  11505.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11506.                         return $this->raiseError('%s conflicts with PHP extension "' .
  11507.                             $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  11508.                     } else {
  11509.                         return $this->warning('warning: %s conflicts with PHP extension "' .
  11510.                             $dep['name'] . '"' . $extra . ', installed version is ' . $version);
  11511.                     }
  11512.                 }
  11513.             }
  11514.         }
  11515.         if (isset($dep['recommended'])) {
  11516.             if (version_compare($version, $dep['recommended'], '==')) {
  11517.                 return true;
  11518.             } else {
  11519.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11520.                     return $this->raiseError('%s dependency: PHP extension ' . $dep['name'] .
  11521.                         ' version "' . $version . '"' .
  11522.                         ' is not the recommended version "' . $dep['recommended'] .
  11523.                         '", but may be compatible, use --force to install');
  11524.                 } else {
  11525.                     return $this->warning('warning: %s dependency: PHP extension ' .
  11526.                         $dep['name'] . ' version "' . $version . '"' .
  11527.                         ' is not the recommended version "' . $dep['recommended'].'"');
  11528.                 }
  11529.             }
  11530.         }
  11531.         return true;
  11532.     }
  11533.  
  11534.     function validatePhpDependency($dep)
  11535.     {
  11536.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  11537.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  11538.             return true;
  11539.         }
  11540.         $version = $this->phpversion();
  11541.         $extra = $this->_getExtraString($dep);
  11542.         if (isset($dep['exclude'])) {
  11543.             if (!is_array($dep['exclude'])) {
  11544.                 $dep['exclude'] = array($dep['exclude']);
  11545.             }
  11546.         }
  11547.         if (isset($dep['min'])) {
  11548.             if (!version_compare($version, $dep['min'], '>=')) {
  11549.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11550.                     return $this->raiseError('%s requires PHP' .
  11551.                         $extra . ', installed version is ' . $version);
  11552.                 } else {
  11553.                     return $this->warning('warning: %s requires PHP' .
  11554.                         $extra . ', installed version is ' . $version);
  11555.                 }
  11556.             }
  11557.         }
  11558.         if (isset($dep['max'])) {
  11559.             if (!version_compare($version, $dep['max'], '<=')) {
  11560.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11561.                     return $this->raiseError('%s requires PHP' .
  11562.                         $extra . ', installed version is ' . $version);
  11563.                 } else {
  11564.                     return $this->warning('warning: %s requires PHP' .
  11565.                         $extra . ', installed version is ' . $version);
  11566.                 }
  11567.             }
  11568.         }
  11569.         if (isset($dep['exclude'])) {
  11570.             foreach ($dep['exclude'] as $exclude) {
  11571.                 if (version_compare($version, $exclude, '==')) {
  11572.                     if (!isset($this->_options['nodeps']) &&
  11573.                           !isset($this->_options['force'])) {
  11574.                         return $this->raiseError('%s is not compatible with PHP version ' .
  11575.                             $exclude);
  11576.                     } else {
  11577.                         return $this->warning(
  11578.                             'warning: %s is not compatible with PHP version ' .
  11579.                             $exclude);
  11580.                     }
  11581.                 }
  11582.             }
  11583.         }
  11584.         return true;
  11585.     }
  11586.  
  11587.     /**
  11588.      * This makes unit-testing a heck of a lot easier
  11589.      */
  11590.     function getPEARVersion()
  11591.     {
  11592.         return '1.5.0a2';
  11593.     }
  11594.  
  11595.     function validatePearinstallerDependency($dep)
  11596.     {
  11597.         $pearversion = $this->getPEARVersion();
  11598.         $extra = $this->_getExtraString($dep);
  11599.         if (isset($dep['exclude'])) {
  11600.             if (!is_array($dep['exclude'])) {
  11601.                 $dep['exclude'] = array($dep['exclude']);
  11602.             }
  11603.         }
  11604.         if (version_compare($pearversion, $dep['min'], '<')) {
  11605.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11606.                 return $this->raiseError('%s requires PEAR Installer' . $extra .
  11607.                     ', installed version is ' . $pearversion);
  11608.             } else {
  11609.                 return $this->warning('warning: %s requires PEAR Installer' . $extra .
  11610.                     ', installed version is ' . $pearversion);
  11611.             }
  11612.         }
  11613.         if (isset($dep['max'])) {
  11614.             if (version_compare($pearversion, $dep['max'], '>')) {
  11615.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11616.                     return $this->raiseError('%s requires PEAR Installer' . $extra .
  11617.                         ', installed version is ' . $pearversion);
  11618.                 } else {
  11619.                     return $this->warning('warning: %s requires PEAR Installer' . $extra .
  11620.                         ', installed version is ' . $pearversion);
  11621.                 }
  11622.             }
  11623.         }
  11624.         if (isset($dep['exclude'])) {
  11625.             if (!isset($dep['exclude'][0])) {
  11626.                 $dep['exclude'] = array($dep['exclude']);
  11627.             }
  11628.             foreach ($dep['exclude'] as $exclude) {
  11629.                 if (version_compare($exclude, $pearversion, '==')) {
  11630.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11631.                         return $this->raiseError('%s is not compatible with PEAR Installer ' .
  11632.                             'version ' . $exclude);
  11633.                     } else {
  11634.                         return $this->warning('warning: %s is not compatible with PEAR ' .
  11635.                             'Installer version ' . $exclude);
  11636.                     }
  11637.                 }
  11638.             }
  11639.         }
  11640.         return true;
  11641.     }
  11642.  
  11643.     function validateSubpackageDependency($dep, $required, $params)
  11644.     {
  11645.         return $this->validatePackageDependency($dep, $required, $params);
  11646.     }
  11647.  
  11648.     /**
  11649.      * @param array dependency information (2.0 format)
  11650.      * @param boolean whether this is a required dependency
  11651.      * @param array a list of downloaded packages to be installed, if any
  11652.      * @param boolean if true, then deps on pear.php.net that fail will also check
  11653.      *                against pecl.php.net packages to accomodate extensions that have
  11654.      *                moved to pecl.php.net from pear.php.net
  11655.      */
  11656.     function validatePackageDependency($dep, $required, $params, $depv1 = false)
  11657.     {
  11658.         if ($this->_state != PEAR_VALIDATE_INSTALLING &&
  11659.               $this->_state != PEAR_VALIDATE_DOWNLOADING) {
  11660.             return true;
  11661.         }
  11662.         if (isset($dep['providesextension'])) {
  11663.             if ($this->extension_loaded($dep['providesextension'])) {
  11664.                 $save = $dep;
  11665.                 $subdep = $dep;
  11666.                 $subdep['name'] = $subdep['providesextension'];
  11667.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  11668.                 $ret = $this->validateExtensionDependency($subdep, $required);
  11669.                 PEAR::popErrorHandling();
  11670.                 if (!PEAR::isError($ret)) {
  11671.                     return true;
  11672.                 }
  11673.             }
  11674.         }
  11675.         if ($this->_state == PEAR_VALIDATE_INSTALLING) {
  11676.             return $this->_validatePackageInstall($dep, $required, $depv1);
  11677.         }
  11678.         if ($this->_state == PEAR_VALIDATE_DOWNLOADING) {
  11679.             return $this->_validatePackageDownload($dep, $required, $params, $depv1);
  11680.         }
  11681.     }
  11682.  
  11683.     function _validatePackageDownload($dep, $required, $params, $depv1 = false)
  11684.     {
  11685.         $dep['package'] = $dep['name'];
  11686.         if (isset($dep['uri'])) {
  11687.             $dep['channel'] = '__uri';
  11688.         }
  11689.         $depname = $this->_registry->parsedPackageNameToString($dep, true);
  11690.         $found = false;
  11691.         foreach ($params as $param) {
  11692.             if ($param->isEqual(
  11693.                   array('package' => $dep['name'],
  11694.                         'channel' => $dep['channel']))) {
  11695.                 $found = true;
  11696.                 break;
  11697.             }
  11698.             if ($depv1 && $dep['channel'] == 'pear.php.net') {
  11699.                 if ($param->isEqual(
  11700.                   array('package' => $dep['name'],
  11701.                         'channel' => 'pecl.php.net'))) {
  11702.                     $found = true;
  11703.                     break;
  11704.                 }
  11705.             }
  11706.         }
  11707.         if (!$found && isset($dep['providesextension'])) {
  11708.             foreach ($params as $param) {
  11709.                 if ($param->isExtension($dep['providesextension'])) {
  11710.                     $found = true;
  11711.                     break;
  11712.                 }
  11713.             }
  11714.         }
  11715.         if ($found) {
  11716.             $version = $param->getVersion();
  11717.             $installed = false;
  11718.             $downloaded = true;
  11719.         } else {
  11720.             if ($this->_registry->packageExists($dep['name'], $dep['channel'])) {
  11721.                 $installed = true;
  11722.                 $downloaded = false;
  11723.                 $version = $this->_registry->packageinfo($dep['name'], 'version',
  11724.                     $dep['channel']);
  11725.             } else {
  11726.                 if ($dep['channel'] == 'pecl.php.net' && $this->_registry->packageExists($dep['name'],
  11727.                       'pear.php.net')) {
  11728.                     $installed = true;
  11729.                     $downloaded = false;
  11730.                     $version = $this->_registry->packageinfo($dep['name'], 'version',
  11731.                         'pear.php.net');
  11732.                 } else {
  11733.                     $version = 'not installed or downloaded';
  11734.                     $installed = false;
  11735.                     $downloaded = false;
  11736.                 }
  11737.             }
  11738.         }
  11739.         $extra = $this->_getExtraString($dep);
  11740.         if (isset($dep['exclude'])) {
  11741.             if (!is_array($dep['exclude'])) {
  11742.                 $dep['exclude'] = array($dep['exclude']);
  11743.             }
  11744.         }
  11745.         if (!isset($dep['min']) && !isset($dep['max']) &&
  11746.               !isset($dep['recommended']) && !isset($dep['exclude'])) {
  11747.             if ($installed || $downloaded) {
  11748.                 $installed = $installed ? 'installed' : 'downloaded';
  11749.                 if (isset($dep['conflicts'])) {
  11750.                     if ($version) {
  11751.                         $rest = ", $installed version is " . $version;
  11752.                     } else {
  11753.                         $rest = '';
  11754.                     }
  11755.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11756.                         return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  11757.                             $extra . $rest);
  11758.                     } else {
  11759.                         return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  11760.                             $extra . $rest);
  11761.                     }
  11762.                 }
  11763.                 return true;
  11764.             } else {
  11765.                 if (isset($dep['conflicts'])) {
  11766.                     return true;
  11767.                 }
  11768.                 if ($required) {
  11769.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11770.                         return $this->raiseError('%s requires package "' . $depname . '"' .
  11771.                             $extra);
  11772.                     } else {
  11773.                         return $this->warning('warning: %s requires package "' . $depname . '"' .
  11774.                             $extra);
  11775.                     }
  11776.                 } else {
  11777.                     return $this->warning('%s can optionally use package "' . $depname . '"' .
  11778.                         $extra);
  11779.                 }
  11780.             }
  11781.         }
  11782.         if (!$installed && !$downloaded) {
  11783.             if (isset($dep['conflicts'])) {
  11784.                 return true;
  11785.             }
  11786.             if ($required) {
  11787.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11788.                     return $this->raiseError('%s requires package "' . $depname . '"' .
  11789.                         $extra);
  11790.                 } else {
  11791.                     return $this->warning('warning: %s requires package "' . $depname . '"' .
  11792.                         $extra);
  11793.                 }
  11794.             } else {
  11795.                 return $this->warning('%s can optionally use package "' . $depname . '"' .
  11796.                     $extra);
  11797.             }
  11798.         }
  11799.         $fail = false;
  11800.         if (isset($dep['min'])) {
  11801.             if (version_compare($version, $dep['min'], '<')) {
  11802.                 $fail = true;
  11803.             }
  11804.         }
  11805.         if (isset($dep['max'])) {
  11806.             if (version_compare($version, $dep['max'], '>')) {
  11807.                 $fail = true;
  11808.             }
  11809.         }
  11810.         if ($fail && !isset($dep['conflicts'])) {
  11811.             $installed = $installed ? 'installed' : 'downloaded';
  11812.             $dep['package'] = $dep['name'];
  11813.             $dep = $this->_registry->parsedPackageNameToString($dep, true);
  11814.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11815.                 return $this->raiseError('%s requires package "' . $depname . '"' .
  11816.                     $extra . ", $installed version is " . $version);
  11817.             } else {
  11818.                 return $this->warning('warning: %s requires package "' . $depname . '"' .
  11819.                     $extra . ", $installed version is " . $version);
  11820.             }
  11821.         } elseif ((isset($dep['min']) || isset($dep['max'])) && !$fail &&
  11822.               isset($dep['conflicts']) && !isset($dep['exclude'])) {
  11823.             $installed = $installed ? 'installed' : 'downloaded';
  11824.             if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11825.                 return $this->raiseError('%s conflicts with package "' . $depname . '"' . $extra .
  11826.                     ", $installed version is " . $version);
  11827.             } else {
  11828.                 return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  11829.                     $extra . ", $installed version is " . $version);
  11830.             }
  11831.         }
  11832.         if (isset($dep['exclude'])) {
  11833.             $installed = $installed ? 'installed' : 'downloaded';
  11834.             foreach ($dep['exclude'] as $exclude) {
  11835.                 if (version_compare($version, $exclude, '==') && !isset($dep['conflicts'])) {
  11836.                     if (!isset($this->_options['nodeps']) &&
  11837.                           !isset($this->_options['force'])) {
  11838.                         return $this->raiseError('%s is not compatible with ' .
  11839.                             $installed . ' package "' .
  11840.                             $depname . '" version ' .
  11841.                             $exclude);
  11842.                     } else {
  11843.                         return $this->warning('warning: %s is not compatible with ' .
  11844.                             $installed . ' package "' .
  11845.                             $depname . '" version ' .
  11846.                             $exclude);
  11847.                     }
  11848.                 } elseif (version_compare($version, $exclude, '!=') && isset($dep['conflicts'])) {
  11849.                     $installed = $installed ? 'installed' : 'downloaded';
  11850.                     if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11851.                         return $this->raiseError('%s conflicts with package "' . $depname . '"' .
  11852.                             $extra . ", $installed version is " . $version);
  11853.                     } else {
  11854.                         return $this->warning('warning: %s conflicts with package "' . $depname . '"' .
  11855.                             $extra . ", $installed version is " . $version);
  11856.                     }
  11857.                 }
  11858.             }
  11859.         }
  11860.         if (isset($dep['recommended'])) {
  11861.             $installed = $installed ? 'installed' : 'downloaded';
  11862.             if (version_compare($version, $dep['recommended'], '==')) {
  11863.                 return true;
  11864.             } else {
  11865.                 if (!$found && $installed) {
  11866.                     $param = $this->_registry->getPackage($dep['name'], $dep['channel']);
  11867.                 }
  11868.                 if ($param) {
  11869.                     $found = false;
  11870.                     foreach ($params as $parent) {
  11871.                         if ($parent->isEqual($this->_currentPackage)) {
  11872.                             $found = true;
  11873.                             break;
  11874.                         }
  11875.                     }
  11876.                     if ($found) {
  11877.                         if ($param->isCompatible($parent)) {
  11878.                             return true;
  11879.                         }
  11880.                     } else { // this is for validPackage() calls
  11881.                         $parent = $this->_registry->getPackage($this->_currentPackage['package'],
  11882.                             $this->_currentPackage['channel']);
  11883.                         if ($parent !== null) {
  11884.                             if ($param->isCompatible($parent)) {
  11885.                                 return true;
  11886.                             }
  11887.                         }
  11888.                     }
  11889.                 }
  11890.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force']) &&
  11891.                       !isset($this->_options['loose'])) {
  11892.                     return $this->raiseError('%s dependency package "' . $depname .
  11893.                         '" ' . $installed . ' version ' . $version . 
  11894.                         ' is not the recommended version ' . $dep['recommended'] .
  11895.                         ', but may be compatible, use --force to install');
  11896.                 } else {
  11897.                     return $this->warning('warning: %s dependency package "' . $depname .
  11898.                         '" ' . $installed . ' version ' . $version .
  11899.                         ' is not the recommended version ' . $dep['recommended']);
  11900.                 }
  11901.             }
  11902.         }
  11903.         return true;
  11904.     }
  11905.  
  11906.     function _validatePackageInstall($dep, $required, $depv1 = false)
  11907.     {
  11908.         return $this->_validatePackageDownload($dep, $required, array(), $depv1);
  11909.     }
  11910.  
  11911.     /**
  11912.      * Verify that uninstalling packages passed in to command line is OK.
  11913.      *
  11914.      * @param PEAR_Installer $dl
  11915.      * @return PEAR_Error|true
  11916.      */
  11917.     function validatePackageUninstall(&$dl)
  11918.     {
  11919.         if (PEAR::isError($this->_dependencydb)) {
  11920.             return $this->_dependencydb;
  11921.         }
  11922.         $params = array();
  11923.         // construct an array of "downloaded" packages to fool the package dependency checker
  11924.         // into using these to validate uninstalls of circular dependencies
  11925.         $downloaded = &$dl->getUninstallPackages();
  11926.         foreach ($downloaded as $i => $pf) {
  11927.             if (!class_exists('PEAR_Downloader_Package')) {
  11928.                 require_once 'phar://go-pear.phar/PEAR/Downloader/Package.php';
  11929.             }
  11930.             $dp = &new PEAR_Downloader_Package($dl);
  11931.             $dp->setPackageFile($downloaded[$i]);
  11932.             $params[$i] = &$dp;
  11933.         }
  11934.         $deps = $this->_dependencydb->getDependentPackageDependencies($this->_currentPackage);
  11935.         $fail = false;
  11936.         if ($deps) {
  11937.             foreach ($deps as $channel => $info) {
  11938.                 foreach ($info as $package => $ds) {
  11939.                     foreach ($ds as $d) {
  11940.                         $d['dep']['package'] = $d['dep']['name'];
  11941.                         $checker = &new PEAR_Dependency2($this->_config, $this->_options,
  11942.                             array('channel' => $channel, 'package' => $package), $this->_state);
  11943.                         $dep = $d['dep'];
  11944.                         $required = $d['type'] == 'required';
  11945.                         $ret = $checker->_validatePackageUninstall($dep, $required, $params, $dl);
  11946.                         if (is_array($ret)) {
  11947.                             $dl->log(0, $ret[0]);
  11948.                         } elseif (PEAR::isError($ret)) {
  11949.                             $dl->log(0, $ret->getMessage());
  11950.                             $fail = true;
  11951.                         }
  11952.                     }
  11953.                 }
  11954.             }
  11955.         }
  11956.         if ($fail) {
  11957.             if (isset($this->_options['nodeps']) || isset($this->_options['force'])) {
  11958.                 return $this->warning(
  11959.                     'warning: %s should not be uninstalled, other installed packages depend ' .
  11960.                     'on this package');
  11961.             } else {
  11962.                 return $this->raiseError(
  11963.                     '%s cannot be uninstalled, other installed packages depend on this package');
  11964.             }
  11965.         }
  11966.         return true;
  11967.     }
  11968.  
  11969.     function _validatePackageUninstall($dep, $required, $params, &$dl)
  11970.     {
  11971.         $dep['package'] = $dep['name'];
  11972.         $depname = $this->_registry->parsedPackageNameToString($dep, true);
  11973.         $found = false;
  11974.         foreach ($params as $param) {
  11975.             if ($param->isEqual($this->_currentPackage)) {
  11976.                 $found = true;
  11977.                 break;
  11978.             }
  11979.         }
  11980.         $version = $this->_registry->packageinfo($dep['name'], 'version',
  11981.             $dep['channel']);
  11982.         if (!$version) {
  11983.             return true;
  11984.         }
  11985.         $extra = $this->_getExtraString($dep);
  11986.         if (isset($dep['exclude'])) {
  11987.             if (!is_array($dep['exclude'])) {
  11988.                 $dep['exclude'] = array($dep['exclude']);
  11989.             }
  11990.         }
  11991.         if (isset($dep['conflicts'])) {
  11992.             return true; // uninstall OK - these packages conflict (probably installed with --force)
  11993.         }
  11994.         if (!isset($dep['min']) && !isset($dep['max'])) {
  11995.             if ($required) {
  11996.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  11997.                     return $this->raiseError('"' . $depname . '" is required by ' .
  11998.                         'installed package %s' . $extra);
  11999.                 } else {
  12000.                     return $this->warning('warning: "' . $depname . '" is required by ' .
  12001.                         'installed package %s' . $extra);
  12002.                 }
  12003.             } else {
  12004.                 return $this->warning('"' . $depname . '" can be optionally used by ' .
  12005.                         'installed package %s' . $extra);
  12006.             }
  12007.         }
  12008.         $fail = false;
  12009.         if (isset($dep['min'])) {
  12010.             if (version_compare($version, $dep['min'], '>=')) {
  12011.                 $fail = true;
  12012.             }
  12013.         }
  12014.         if (isset($dep['max'])) {
  12015.             if (version_compare($version, $dep['max'], '<=')) {
  12016.                 $fail = true;
  12017.             }
  12018.         }
  12019.         if ($fail) {
  12020.             if ($found) {
  12021.                 if (!isset($dl->___checked[$this->_currentPackage['channel']]
  12022.                       [$this->_currentPackage['package']])) {
  12023.                     $dl->___checked[$this->_currentPackage['channel']]
  12024.                       [$this->_currentPackage['package']] = true;
  12025.                     $deps = $this->_dependencydb->getDependentPackageDependencies(
  12026.                         $this->_currentPackage);
  12027.                     if ($deps) {
  12028.                         foreach ($deps as $channel => $info) {
  12029.                             foreach ($info as $package => $ds) {
  12030.                                 foreach ($ds as $d) {
  12031.                                     $d['dep']['package'] = $d['dep']['name'];
  12032.                                     $checker = &new PEAR_Dependency2($this->_config, $this->_options,
  12033.                                         array('channel' => $channel, 'package' => $package),
  12034.                                         $this->_state);
  12035.                                     $dep = $d['dep'];
  12036.                                     $required = $d['type'] == 'required';
  12037.                                     $ret = $checker->_validatePackageUninstall($dep, $required, $params,
  12038.                                         $dl);
  12039.                                     if (PEAR::isError($ret)) {
  12040.                                         $fail = true;
  12041.                                         break 3;
  12042.                                     }
  12043.                                 }
  12044.                             }
  12045.                             $fail = false;
  12046.                         }
  12047.                     }
  12048.                 } else {
  12049.                     return true;
  12050.                 }
  12051.             }
  12052.             if (!$fail) {
  12053.                 return true;
  12054.             }
  12055.             if ($required) {
  12056.                 if (!isset($this->_options['nodeps']) && !isset($this->_options['force'])) {
  12057.                     return $this->raiseError($depname . $extra . ' is required by installed package' .
  12058.                         ' "%s"');
  12059.                 } else {
  12060.                     return $this->warning('warning: ' . $depname . $extra .
  12061.                         ' is required by installed package "%s"');
  12062.                 }
  12063.             } else {
  12064.                 return $this->warning($depname . $extra . ' can be optionally used by installed package' .
  12065.                         ' "%s"');
  12066.             }
  12067.         }
  12068.         return true;
  12069.     }
  12070.  
  12071.     /**
  12072.      * validate a downloaded package against installed packages
  12073.      * 
  12074.      * As of PEAR 1.4.3, this will only validate
  12075.      *
  12076.      * @param array|PEAR_Downloader_Package|PEAR_PackageFile_v1|PEAR_PackageFile_v2
  12077.      *              $pkg package identifier (either
  12078.      *                   array('package' => blah, 'channel' => blah) or an array with
  12079.      *                   index 'info' referencing an object)
  12080.      * @param PEAR_Downloader $dl
  12081.      * @param array $params full list of packages to install
  12082.      * @return true|PEAR_Error
  12083.      */
  12084.     function validatePackage($pkg, &$dl, $params = array())
  12085.     {
  12086.         if (is_array($pkg) && isset($pkg['info'])) {
  12087.             $deps = $this->_dependencydb->getDependentPackageDependencies($pkg['info']);
  12088.         } else {
  12089.             $deps = $this->_dependencydb->getDependentPackageDependencies($pkg);
  12090.         }
  12091.         $fail = false;
  12092.         if ($deps) {
  12093.             if (!class_exists('PEAR_Downloader_Package')) {
  12094.                 require_once 'phar://go-pear.phar/PEAR/Downloader/Package.php';
  12095.             }
  12096.             $dp = &new PEAR_Downloader_Package($dl);
  12097.             if (is_object($pkg)) {
  12098.                 $dp->setPackageFile($pkg);
  12099.             } else {
  12100.                 $dp->setDownloadURL($pkg);
  12101.             }
  12102.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  12103.             foreach ($deps as $channel => $info) {
  12104.                 foreach ($info as $package => $ds) {
  12105.                     foreach ($params as $packd) {
  12106.                         if (strtolower($packd->getPackage()) == strtolower($package) &&
  12107.                               $packd->getChannel() == $channel) {
  12108.                             $dl->log(3, 'skipping installed package check of "' .
  12109.                                         $this->_registry->parsedPackageNameToString(
  12110.                                             array('channel' => $channel, 'package' => $package),
  12111.                                             true) .
  12112.                                         '", version "' . $packd->getVersion() . '" will be ' .
  12113.                                         'downloaded and installed');
  12114.                             continue 2; // jump to next package
  12115.                         }
  12116.                     }
  12117.                     foreach ($ds as $d) {
  12118.                         $checker = &new PEAR_Dependency2($this->_config, $this->_options,
  12119.                             array('channel' => $channel, 'package' => $package), $this->_state);
  12120.                         $dep = $d['dep'];
  12121.                         $required = $d['type'] == 'required';
  12122.                         $ret = $checker->_validatePackageDownload($dep, $required, array(&$dp));
  12123.                         if (is_array($ret)) {
  12124.                             $dl->log(0, $ret[0]);
  12125.                         } elseif (PEAR::isError($ret)) {
  12126.                             $dl->log(0, $ret->getMessage());
  12127.                             $fail = true;
  12128.                         }
  12129.                     }
  12130.                 }
  12131.             }
  12132.             PEAR::popErrorHandling();
  12133.         }
  12134.         if ($fail) {
  12135.             return $this->raiseError(
  12136.                 '%s cannot be installed, conflicts with installed packages');
  12137.         }
  12138.         return true;
  12139.     }
  12140.  
  12141.     /**
  12142.      * validate a package.xml 1.0 dependency
  12143.      */
  12144.     function validateDependency1($dep, $params = array())
  12145.     {
  12146.         if (!isset($dep['optional'])) {
  12147.             $dep['optional'] = 'no';
  12148.         }
  12149.         list($newdep, $type) = $this->normalizeDep($dep);
  12150.         if (!$newdep) {
  12151.             return $this->raiseError("Invalid Dependency");
  12152.         }
  12153.         if (method_exists($this, "validate{$type}Dependency")) {
  12154.             return $this->{"validate{$type}Dependency"}($newdep, $dep['optional'] == 'no',
  12155.                 $params, true);
  12156.         }
  12157.     }
  12158.  
  12159.     /**
  12160.      * Convert a 1.0 dep into a 2.0 dep
  12161.      */
  12162.     function normalizeDep($dep)
  12163.     {
  12164.         $types = array(
  12165.             'pkg' => 'Package',
  12166.             'ext' => 'Extension',
  12167.             'os' => 'Os',
  12168.             'php' => 'Php'
  12169.         );
  12170.         if (isset($types[$dep['type']])) {
  12171.             $type = $types[$dep['type']];
  12172.         } else {
  12173.             return array(false, false);
  12174.         }
  12175.         $newdep = array();
  12176.         switch ($type) {
  12177.             case 'Package' :
  12178.                 $newdep['channel'] = 'pear.php.net';
  12179.             case 'Extension' :
  12180.             case 'Os' :
  12181.                 $newdep['name'] = $dep['name'];
  12182.             break;
  12183.         }
  12184.         $dep['rel'] = PEAR_Dependency2::signOperator($dep['rel']);
  12185.         switch ($dep['rel']) {
  12186.             case 'has' :
  12187.                 return array($newdep, $type);
  12188.             break;
  12189.             case 'not' :
  12190.                 $newdep['conflicts'] = true;
  12191.             break;
  12192.             case '>=' :
  12193.             case '>' :
  12194.                 $newdep['min'] = $dep['version'];
  12195.                 if ($dep['rel'] == '>') {
  12196.                     $newdep['exclude'] = $dep['version'];
  12197.                 }
  12198.             break;
  12199.             case '<=' :
  12200.             case '<' :
  12201.                 $newdep['max'] = $dep['version'];
  12202.                 if ($dep['rel'] == '<') {
  12203.                     $newdep['exclude'] = $dep['version'];
  12204.                 }
  12205.             break;
  12206.             case 'ne' :
  12207.             case '!=' :
  12208.                 $newdep['min'] = '0';
  12209.                 $newdep['max'] = '100000';
  12210.                 $newdep['exclude'] = $dep['version'];
  12211.             break;
  12212.             case '==' :
  12213.                 $newdep['min'] = $dep['version'];
  12214.                 $newdep['max'] = $dep['version'];
  12215.             break;
  12216.         }
  12217.         if ($type == 'Php') {
  12218.             if (!isset($newdep['min'])) {
  12219.                 $newdep['min'] = '4.2.0';
  12220.             }
  12221.             if (!isset($newdep['max'])) {
  12222.                 $newdep['max'] = '6.0.0';
  12223.             }
  12224.         }
  12225.         return array($newdep, $type);
  12226.     }
  12227.  
  12228.     /**
  12229.      * Converts text comparing operators to them sign equivalents
  12230.      *
  12231.      * Example: 'ge' to '>='
  12232.      *
  12233.      * @access public
  12234.      * @param  string Operator
  12235.      * @return string Sign equivalent
  12236.      */
  12237.     function signOperator($operator)
  12238.     {
  12239.         switch($operator) {
  12240.             case 'lt': return '<';
  12241.             case 'le': return '<=';
  12242.             case 'gt': return '>';
  12243.             case 'ge': return '>=';
  12244.             case 'eq': return '==';
  12245.             case 'ne': return '!=';
  12246.             default:
  12247.                 return $operator;
  12248.         }
  12249.     }
  12250.  
  12251.     function raiseError($msg)
  12252.     {
  12253.         if (isset($this->_options['ignore-errors'])) {
  12254.             return $this->warning($msg);
  12255.         }
  12256.         return PEAR::raiseError(sprintf($msg, $this->_registry->parsedPackageNameToString(
  12257.             $this->_currentPackage, true)));
  12258.     }
  12259.  
  12260.     function warning($msg)
  12261.     {
  12262.         return array(sprintf($msg, $this->_registry->parsedPackageNameToString(
  12263.             $this->_currentPackage, true)));
  12264.     }
  12265. }
  12266. ?><?php
  12267. /**
  12268.  * PEAR_DependencyDB, advanced installed packages dependency database
  12269.  *
  12270.  * PHP versions 4 and 5
  12271.  *
  12272.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  12273.  * that is available through the world-wide-web at the following URI:
  12274.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  12275.  * the PHP License and are unable to obtain it through the web, please
  12276.  * send a note to license@php.net so we can mail you a copy immediately.
  12277.  *
  12278.  * @category   pear
  12279.  * @package    PEAR
  12280.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  12281.  * @author     Greg Beaver <cellog@php.net>
  12282.  * @copyright  1997-2006 The PHP Group
  12283.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  12284.  * @version    CVS: $Id: DependencyDB.php,v 1.33 2006/05/25 21:40:36 cellog Exp $
  12285.  * @link       http://pear.php.net/package/PEAR
  12286.  * @since      File available since Release 1.4.0a1
  12287.  */
  12288.  
  12289. /**
  12290.  * Needed for error handling
  12291.  */
  12292. require_once 'phar://go-pear.phar/PEAR.php';
  12293. require_once 'phar://go-pear.phar/PEAR/Config.php';
  12294.  
  12295. $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE'] = array();
  12296. /**
  12297.  * Track dependency relationships between installed packages
  12298.  * @category   pear
  12299.  * @package    PEAR
  12300.  * @author     Greg Beaver <cellog@php.net>
  12301.  * @author     Tomas V.V.Cox <cox@idec.net.com>
  12302.  * @copyright  1997-2006 The PHP Group
  12303.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  12304.  * @version    Release: @package_version@
  12305.  * @link       http://pear.php.net/package/PEAR
  12306.  * @since      Class available since Release 1.4.0a1
  12307.  */
  12308. class PEAR_DependencyDB
  12309. {
  12310.     // {{{ properties
  12311.  
  12312.     /**
  12313.      * This is initialized by {@link setConfig()}
  12314.      * @var PEAR_Config
  12315.      * @access private
  12316.      */
  12317.     var $_config;
  12318.     /**
  12319.      * This is initialized by {@link setConfig()}
  12320.      * @var PEAR_Registry
  12321.      * @access private
  12322.      */
  12323.     var $_registry;
  12324.     /**
  12325.      * Filename of the dependency DB (usually .depdb)
  12326.      * @var string
  12327.      * @access private
  12328.      */
  12329.     var $_depdb = false;
  12330.     /**
  12331.      * File name of the lockfile (usually .depdblock)
  12332.      * @var string
  12333.      * @access private
  12334.      */
  12335.     var $_lockfile = false;
  12336.     /**
  12337.      * Open file resource for locking the lockfile
  12338.      * @var resource|false
  12339.      * @access private
  12340.      */
  12341.     var $_lockFp = false;
  12342.     /**
  12343.      * API version of this class, used to validate a file on-disk
  12344.      * @var string
  12345.      * @access private
  12346.      */
  12347.     var $_version = '1.0';
  12348.     /**
  12349.      * Cached dependency database file
  12350.      * @var array|null
  12351.      * @access private
  12352.      */
  12353.     var $_cache;
  12354.  
  12355.     // }}}
  12356.     // {{{ & singleton()
  12357.  
  12358.     /**
  12359.      * Get a raw dependency database.  Calls setConfig() and assertDepsDB()
  12360.      * @param PEAR_Config
  12361.      * @param string|false full path to the dependency database, or false to use default
  12362.      * @return PEAR_DependencyDB|PEAR_Error
  12363.      * @static
  12364.      */
  12365.     function &singleton(&$config, $depdb = false)
  12366.     {
  12367.         if (!isset($GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
  12368.               [$config->get('php_dir', null, 'pear.php.net')])) {
  12369.             $a = new PEAR_DependencyDB;
  12370.             $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
  12371.               [$config->get('php_dir', null, 'pear.php.net')] = &$a;
  12372.             $a->setConfig($config, $depdb);
  12373.             if (PEAR::isError($e = $a->assertDepsDB())) {
  12374.                 return $e;
  12375.             }
  12376.         }
  12377.         return $GLOBALS['_PEAR_DEPENDENCYDB_INSTANCE']
  12378.               [$config->get('php_dir', null, 'pear.php.net')];
  12379.     }
  12380.  
  12381.     /**
  12382.      * Set up the registry/location of dependency DB
  12383.      * @param PEAR_Config|false
  12384.      * @param string|false full path to the dependency database, or false to use default
  12385.      */
  12386.     function setConfig(&$config, $depdb = false)
  12387.     {
  12388.         if (!$config) {
  12389.             $this->_config = &PEAR_Config::singleton();
  12390.         } else {
  12391.             $this->_config = &$config;
  12392.         }
  12393.         $this->_registry = &$this->_config->getRegistry();
  12394.         if (!$depdb) {
  12395.             $this->_depdb = $this->_config->get('php_dir', null, 'pear.php.net') .
  12396.                 DIRECTORY_SEPARATOR . '.depdb';
  12397.         } else {
  12398.             $this->_depdb = $depdb;
  12399.         }
  12400.         $this->_lockfile = dirname($this->_depdb) . DIRECTORY_SEPARATOR . '.depdblock';
  12401.     }
  12402.     // }}}
  12403.  
  12404.     function hasWriteAccess()
  12405.     {
  12406.         if (!file_exists($this->_depdb)) {
  12407.             $dir = $this->_depdb;
  12408.             while ($dir && $dir != '.') {
  12409.                 $dir = dirname($dir); // cd ..
  12410.                 if ($dir != '.' && file_exists($dir)) {
  12411.                     if (is_writeable($dir)) {
  12412.                         return true;
  12413.                     } else {
  12414.                         return false;
  12415.                     }
  12416.                 }
  12417.             }
  12418.             return false;
  12419.         }
  12420.         return is_writeable($this->_depdb);
  12421.     }
  12422.  
  12423.     // {{{ assertDepsDB()
  12424.  
  12425.     /**
  12426.      * Create the dependency database, if it doesn't exist.  Error if the database is
  12427.      * newer than the code reading it.
  12428.      * @return void|PEAR_Error
  12429.      */
  12430.     function assertDepsDB()
  12431.     {
  12432.         if (!is_file($this->_depdb)) {
  12433.             $this->rebuildDB();
  12434.         } else {
  12435.             $depdb = $this->_getDepDB();
  12436.             // Datatype format has been changed, rebuild the Deps DB
  12437.             if ($depdb['_version'] < $this->_version) {
  12438.                 $this->rebuildDB();
  12439.             }
  12440.             if ($depdb['_version']{0} > $this->_version{0}) {
  12441.                 return PEAR::raiseError('Dependency database is version ' .
  12442.                     $depdb['_version'] . ', and we are version ' .
  12443.                     $this->_version . ', cannot continue');
  12444.             }
  12445.         }
  12446.     }
  12447.  
  12448.     /**
  12449.      * Get a list of installed packages that depend on this package
  12450.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  12451.      * @return array|false
  12452.      */
  12453.     function getDependentPackages(&$pkg)
  12454.     {
  12455.         $data = $this->_getDepDB();
  12456.         if (is_object($pkg)) {
  12457.             $channel = strtolower($pkg->getChannel());
  12458.             $package = strtolower($pkg->getPackage());
  12459.         } else {
  12460.             $channel = strtolower($pkg['channel']);
  12461.             $package = strtolower($pkg['package']);
  12462.         }
  12463.         if (isset($data['packages'][$channel][$package])) {
  12464.             return $data['packages'][$channel][$package];
  12465.         }
  12466.         return false;
  12467.     }
  12468.  
  12469.     /**
  12470.      * Get a list of the actual dependencies of installed packages that depend on
  12471.      * a package.
  12472.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  12473.      * @return array|false
  12474.      */
  12475.     function getDependentPackageDependencies(&$pkg)
  12476.     {
  12477.         $data = $this->_getDepDB();
  12478.         if (is_object($pkg)) {
  12479.             $channel = strtolower($pkg->getChannel());
  12480.             $package = strtolower($pkg->getPackage());
  12481.         } else {
  12482.             $channel = strtolower($pkg['channel']);
  12483.             $package = strtolower($pkg['package']);
  12484.         }
  12485.         $depend = $this->getDependentPackages($pkg);
  12486.         if (!$depend) {
  12487.             return false;
  12488.         }
  12489.         $dependencies = array();
  12490.         foreach ($depend as $info) {
  12491.             $temp = $this->getDependencies($info);
  12492.             foreach ($temp as $dep) {
  12493.                 if (strtolower($dep['dep']['channel']) == strtolower($channel) &&
  12494.                       strtolower($dep['dep']['name']) == strtolower($package)) {
  12495.                     $dependencies[$info['channel']][$info['package']][] = $dep;
  12496.                 }
  12497.             }
  12498.         }
  12499.         return $dependencies;
  12500.     }
  12501.  
  12502.     /**
  12503.      * Get a list of dependencies of this installed package
  12504.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array
  12505.      * @return array|false
  12506.      */
  12507.     function getDependencies(&$pkg)
  12508.     {
  12509.         if (is_object($pkg)) {
  12510.             $channel = strtolower($pkg->getChannel());
  12511.             $package = strtolower($pkg->getPackage());
  12512.         } else {
  12513.             $channel = strtolower($pkg['channel']);
  12514.             $package = strtolower($pkg['package']);
  12515.         }
  12516.         $data = $this->_getDepDB();
  12517.         if (isset($data['dependencies'][$channel][$package])) {
  12518.             return $data['dependencies'][$channel][$package];
  12519.         }
  12520.         return false;
  12521.     }
  12522.  
  12523.     /**
  12524.      * Determine whether $parent depends on $child, near or deep
  12525.      * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
  12526.      * @param array|PEAR_PackageFile_v2|PEAR_PackageFile_v2
  12527.      */
  12528.     function dependsOn($parent, $child)
  12529.     {
  12530.         $c = array();
  12531.         $this->_getDepDB();
  12532.         return $this->_dependsOn($parent, $child, $c);
  12533.     }
  12534.     
  12535.     function _dependsOn($parent, $child, &$checked)
  12536.     {
  12537.         if (is_object($parent)) {
  12538.             $channel = strtolower($parent->getChannel());
  12539.             $package = strtolower($parent->getPackage());
  12540.         } else {
  12541.             $channel = strtolower($parent['channel']);
  12542.             $package = strtolower($parent['package']);
  12543.         }
  12544.         if (is_object($child)) {
  12545.             $depchannel = strtolower($child->getChannel());
  12546.             $deppackage = strtolower($child->getPackage());
  12547.         } else {
  12548.             $depchannel = strtolower($child['channel']);
  12549.             $deppackage = strtolower($child['package']);
  12550.         }
  12551.         if (isset($checked[$channel][$package][$depchannel][$deppackage])) {
  12552.             return false; // avoid endless recursion
  12553.         }
  12554.         $checked[$channel][$package][$depchannel][$deppackage] = true;
  12555.         if (!isset($this->_cache['dependencies'][$channel][$package])) {
  12556.             return false;
  12557.         }
  12558.         foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
  12559.             if (isset($info['dep']['uri'])) {
  12560.                 if (is_object($child)) {
  12561.                     if ($info['dep']['uri'] == $child->getURI()) {
  12562.                         return true;
  12563.                     }
  12564.                 } elseif (isset($child['uri'])) {
  12565.                     if ($info['dep']['uri'] == $child['uri']) {
  12566.                         return true;
  12567.                     }
  12568.                 }
  12569.                 return false;
  12570.             }
  12571.             if (strtolower($info['dep']['channel']) == strtolower($depchannel) &&
  12572.                   strtolower($info['dep']['name']) == strtolower($deppackage)) {
  12573.                 return true;
  12574.             }
  12575.         }
  12576.         foreach ($this->_cache['dependencies'][$channel][$package] as $info) {
  12577.             if (isset($info['dep']['uri'])) {
  12578.                 if ($this->_dependsOn(array(
  12579.                         'uri' => $info['dep']['uri'],
  12580.                         'package' => $info['dep']['name']), $child, $checked)) {
  12581.                     return true;
  12582.                 }
  12583.             } else {
  12584.                 if ($this->_dependsOn(array(
  12585.                         'channel' => $info['dep']['channel'],
  12586.                         'package' => $info['dep']['name']), $child, $checked)) {
  12587.                     return true;
  12588.                 }
  12589.             }
  12590.         }
  12591.         return false;
  12592.     }
  12593.  
  12594.     /**
  12595.      * Register dependencies of a package that is being installed or upgraded
  12596.      * @param PEAR_PackageFile_v2|PEAR_PackageFile_v2
  12597.      */
  12598.     function installPackage(&$package)
  12599.     {
  12600.         $data = $this->_getDepDB();
  12601.         unset($this->_cache);
  12602.         $this->_setPackageDeps($data, $package);
  12603.         $this->_writeDepDB($data);
  12604.     }
  12605.  
  12606.     /**
  12607.      * Remove dependencies of a package that is being uninstalled, or upgraded.
  12608.      *
  12609.      * Upgraded packages first uninstall, then install
  12610.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2|array If an array, then it must have
  12611.      *        indices 'channel' and 'package'
  12612.      */
  12613.     function uninstallPackage(&$pkg)
  12614.     {
  12615.         $data = $this->_getDepDB();
  12616.         unset($this->_cache);
  12617.         if (is_object($pkg)) {
  12618.             $channel = strtolower($pkg->getChannel());
  12619.             $package = strtolower($pkg->getPackage());
  12620.         } else {
  12621.             $channel = strtolower($pkg['channel']);
  12622.             $package = strtolower($pkg['package']);
  12623.         }
  12624.         if (!isset($data['dependencies'][$channel][$package])) {
  12625.             return true;
  12626.         }
  12627.         foreach ($data['dependencies'][$channel][$package] as $dep) {
  12628.             $found = false;
  12629.             if (isset($dep['dep']['uri'])) {
  12630.                 $depchannel = '__uri';
  12631.             } else {
  12632.                 $depchannel = strtolower($dep['dep']['channel']);
  12633.             }
  12634.             if (isset($data['packages'][$depchannel][strtolower($dep['dep']['name'])])) {
  12635.                 foreach ($data['packages'][$depchannel][strtolower($dep['dep']['name'])] as
  12636.                       $i => $info) {
  12637.                     if ($info['channel'] == $channel &&
  12638.                           $info['package'] == $package) {
  12639.                         $found = true;
  12640.                         break;
  12641.                     }
  12642.                 }
  12643.             }
  12644.             if ($found) {
  12645.                 unset($data['packages'][$depchannel][strtolower($dep['dep']['name'])][$i]);
  12646.                 if (!count($data['packages'][$depchannel][strtolower($dep['dep']['name'])])) {
  12647.                     unset($data['packages'][$depchannel][strtolower($dep['dep']['name'])]);
  12648.                     if (!count($data['packages'][$depchannel])) {
  12649.                         unset($data['packages'][$depchannel]);
  12650.                     }
  12651.                 } else {
  12652.                     $data['packages'][$depchannel][strtolower($dep['dep']['name'])] =
  12653.                         array_values(
  12654.                             $data['packages'][$depchannel][strtolower($dep['dep']['name'])]);
  12655.                 }
  12656.             }
  12657.         }
  12658.         unset($data['dependencies'][$channel][$package]);
  12659.         if (!count($data['dependencies'][$channel])) {
  12660.             unset($data['dependencies'][$channel]);
  12661.         }
  12662.         if (!count($data['dependencies'])) {
  12663.             unset($data['dependencies']);
  12664.         }
  12665.         if (!count($data['packages'])) {
  12666.             unset($data['packages']);
  12667.         }
  12668.         $this->_writeDepDB($data);
  12669.     }
  12670.  
  12671.     /**
  12672.      * Rebuild the dependency DB by reading registry entries.
  12673.      * @return true|PEAR_Error
  12674.      */
  12675.     function rebuildDB()
  12676.     {
  12677.         $depdb = array('_version' => $this->_version);
  12678.         if (!$this->hasWriteAccess()) {
  12679.             // allow startup for read-only with older Registry
  12680.             return $depdb;
  12681.         }
  12682.         $packages = $this->_registry->listAllPackages();
  12683.         foreach ($packages as $channel => $ps) {
  12684.             foreach ($ps as $package) {
  12685.                 $package = $this->_registry->getPackage($package, $channel);
  12686.                 $this->_setPackageDeps($depdb, $package);
  12687.             }
  12688.         }
  12689.         $error = $this->_writeDepDB($depdb);
  12690.         if (PEAR::isError($error)) {
  12691.             return $error;
  12692.         }
  12693.         $this->_cache = $depdb;
  12694.         return true;
  12695.     }
  12696.  
  12697.     /**
  12698.      * Register usage of the dependency DB to prevent race conditions
  12699.      * @param int one of the LOCK_* constants
  12700.      * @return true|PEAR_Error
  12701.      * @access private
  12702.      */
  12703.     function _lock($mode = LOCK_EX)
  12704.     {
  12705.         if (!eregi('Windows 9', php_uname())) {
  12706.             if ($mode != LOCK_UN && is_resource($this->_lockFp)) {
  12707.                 // XXX does not check type of lock (LOCK_SH/LOCK_EX)
  12708.                 return true;
  12709.             }
  12710.             $open_mode = 'w';
  12711.             // XXX People reported problems with LOCK_SH and 'w'
  12712.             if ($mode === LOCK_SH) {
  12713.                 if (!file_exists($this->_lockfile)) {
  12714.                     touch($this->_lockfile);
  12715.                 } elseif (!is_file($this->_lockfile)) {
  12716.                     return PEAR::raiseError('could not create Dependency lock file, ' .
  12717.                         'it exists and is not a regular file');
  12718.                 }
  12719.                 $open_mode = 'r';
  12720.             }
  12721.  
  12722.             if (!is_resource($this->_lockFp)) {
  12723.                 $this->_lockFp = @fopen($this->_lockfile, $open_mode);
  12724.             }
  12725.             if (!is_resource($this->_lockFp)) {
  12726.                 return PEAR::raiseError("could not create Dependency lock file" .
  12727.                                          (isset($php_errormsg) ? ": " . $php_errormsg : ""));
  12728.             }
  12729.             if (!(int)flock($this->_lockFp, $mode)) {
  12730.                 switch ($mode) {
  12731.                     case LOCK_SH: $str = 'shared';    break;
  12732.                     case LOCK_EX: $str = 'exclusive'; break;
  12733.                     case LOCK_UN: $str = 'unlock';    break;
  12734.                     default:      $str = 'unknown';   break;
  12735.                 }
  12736.                 return PEAR::raiseError("could not acquire $str lock ($this->_lockfile)");
  12737.             }
  12738.         }
  12739.         return true;
  12740.     }
  12741.  
  12742.     /**
  12743.      * Release usage of dependency DB
  12744.      * @return true|PEAR_Error
  12745.      * @access private
  12746.      */
  12747.     function _unlock()
  12748.     {
  12749.         $ret = $this->_lock(LOCK_UN);
  12750.         if (is_resource($this->_lockFp)) {
  12751.             fclose($this->_lockFp);
  12752.         }
  12753.         $this->_lockFp = null;
  12754.         return $ret;
  12755.     }
  12756.  
  12757.     /**
  12758.      * Load the dependency database from disk, or return the cache
  12759.      * @return array|PEAR_Error
  12760.      */
  12761.     function _getDepDB()
  12762.     {
  12763.         if (!$this->hasWriteAccess()) {
  12764.             return array('_version' => $this->_version);
  12765.         }
  12766.         if (isset($this->_cache)) {
  12767.             return $this->_cache;
  12768.         }
  12769.         if (!$fp = fopen($this->_depdb, 'r')) {
  12770.             $err = PEAR::raiseError("Could not open dependencies file `".$this->_depdb."'");
  12771.             return $err;
  12772.         }
  12773.         $rt = get_magic_quotes_runtime();
  12774.         set_magic_quotes_runtime(0);
  12775.         clearstatcache();
  12776.         fclose($fp);
  12777.         $data = unserialize(file_get_contents($this->_depdb));
  12778.         set_magic_quotes_runtime($rt);
  12779.         $this->_cache = $data;
  12780.         return $data;
  12781.     }
  12782.  
  12783.     /**
  12784.      * Write out the dependency database to disk
  12785.      * @param array the database
  12786.      * @return true|PEAR_Error
  12787.      * @access private
  12788.      */
  12789.     function _writeDepDB(&$deps)
  12790.     {
  12791.         if (PEAR::isError($e = $this->_lock(LOCK_EX))) {
  12792.             return $e;
  12793.         }
  12794.         if (!$fp = fopen($this->_depdb, 'wb')) {
  12795.             $this->_unlock();
  12796.             return PEAR::raiseError("Could not open dependencies file `".$this->_depdb."' for writing");
  12797.         }
  12798.         $rt = get_magic_quotes_runtime();
  12799.         set_magic_quotes_runtime(0);
  12800.         fwrite($fp, serialize($deps));
  12801.         set_magic_quotes_runtime($rt);
  12802.         fclose($fp);
  12803.         $this->_unlock();
  12804.         $this->_cache = $deps;
  12805.         return true;
  12806.     }
  12807.  
  12808.     /**
  12809.      * Register all dependencies from a package in the dependencies database, in essence
  12810.      * "installing" the package's dependency information
  12811.      * @param array the database
  12812.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  12813.      * @access private
  12814.      */
  12815.     function _setPackageDeps(&$data, &$pkg)
  12816.     {
  12817.         $pkg->setConfig($this->_config);
  12818.         if ($pkg->getPackagexmlVersion() == '1.0') {
  12819.             $gen = &$pkg->getDefaultGenerator();
  12820.             $deps = $gen->dependenciesToV2();
  12821.         } else {
  12822.             $deps = $pkg->getDeps(true);
  12823.         }
  12824.         if (!$deps) {
  12825.             return;
  12826.         }
  12827.         if (!is_array($data)) {
  12828.             $data = array();
  12829.         }
  12830.         if (!isset($data['dependencies'])) {
  12831.             $data['dependencies'] = array();
  12832.         }
  12833.         if (!isset($data['dependencies'][strtolower($pkg->getChannel())])) {
  12834.             $data['dependencies'][strtolower($pkg->getChannel())] = array();
  12835.         }
  12836.         $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())]
  12837.             = array();
  12838.         if (isset($deps['required']['package'])) {
  12839.             if (!isset($deps['required']['package'][0])) {
  12840.                 $deps['required']['package'] = array($deps['required']['package']);
  12841.             }
  12842.             foreach ($deps['required']['package'] as $dep) {
  12843.                 $this->_registerDep($data, $pkg, $dep, 'required');
  12844.             }
  12845.         }
  12846.         if (isset($deps['optional']['package'])) {
  12847.             if (!isset($deps['optional']['package'][0])) {
  12848.                 $deps['optional']['package'] = array($deps['optional']['package']);
  12849.             }
  12850.             foreach ($deps['optional']['package'] as $dep) {
  12851.                 $this->_registerDep($data, $pkg, $dep, 'optional');
  12852.             }
  12853.         }
  12854.         if (isset($deps['required']['subpackage'])) {
  12855.             if (!isset($deps['required']['subpackage'][0])) {
  12856.                 $deps['required']['subpackage'] = array($deps['required']['subpackage']);
  12857.             }
  12858.             foreach ($deps['required']['subpackage'] as $dep) {
  12859.                 $this->_registerDep($data, $pkg, $dep, 'required');
  12860.             }
  12861.         }
  12862.         if (isset($deps['optional']['subpackage'])) {
  12863.             if (!isset($deps['optional']['subpackage'][0])) {
  12864.                 $deps['optional']['subpackage'] = array($deps['optional']['subpackage']);
  12865.             }
  12866.             foreach ($deps['optional']['subpackage'] as $dep) {
  12867.                 $this->_registerDep($data, $pkg, $dep, 'optional');
  12868.             }
  12869.         }
  12870.         if (isset($deps['group'])) {
  12871.             if (!isset($deps['group'][0])) {
  12872.                 $deps['group'] = array($deps['group']);
  12873.             }
  12874.             foreach ($deps['group'] as $group) {
  12875.                 if (isset($group['package'])) {
  12876.                     if (!isset($group['package'][0])) {
  12877.                         $group['package'] = array($group['package']);
  12878.                     }
  12879.                     foreach ($group['package'] as $dep) {
  12880.                         $this->_registerDep($data, $pkg, $dep, 'optional',
  12881.                             $group['attribs']['name']);
  12882.                     }
  12883.                 }
  12884.                 if (isset($group['subpackage'])) {
  12885.                     if (!isset($group['subpackage'][0])) {
  12886.                         $group['subpackage'] = array($group['subpackage']);
  12887.                     }
  12888.                     foreach ($group['subpackage'] as $dep) {
  12889.                         $this->_registerDep($data, $pkg, $dep, 'optional',
  12890.                             $group['attribs']['name']);
  12891.                     }
  12892.                 }
  12893.             }
  12894.         }
  12895.         if ($data['dependencies'][strtolower($pkg->getChannel())]
  12896.               [strtolower($pkg->getPackage())] == array()) {
  12897.             unset($data['dependencies'][strtolower($pkg->getChannel())]
  12898.               [strtolower($pkg->getPackage())]);
  12899.             if (!count($data['dependencies'][strtolower($pkg->getChannel())])) {
  12900.                 unset($data['dependencies'][strtolower($pkg->getChannel())]);
  12901.             }
  12902.         }
  12903.     }
  12904.  
  12905.     /**
  12906.      * @param array the database
  12907.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  12908.      * @param array the specific dependency
  12909.      * @param required|optional whether this is a required or an optional dep
  12910.      * @param string|false dependency group this dependency is from, or false for ordinary dep
  12911.      */
  12912.     function _registerDep(&$data, &$pkg, $dep, $type, $group = false)
  12913.     {
  12914.         $info = array(
  12915.             'dep' => $dep,
  12916.             'type' => $type,
  12917.             'group' => $group);
  12918.  
  12919.         if (isset($dep['channel'])) {
  12920.             $depchannel = $dep['channel'];
  12921.         } else {
  12922.             $depchannel = '__uri';
  12923.         }
  12924.         if (!isset($data['dependencies'])) {
  12925.             $data['dependencies'] = array();
  12926.         }
  12927.         if (!isset($data['dependencies'][strtolower($pkg->getChannel())])) {
  12928.             $data['dependencies'][strtolower($pkg->getChannel())] = array();
  12929.         }
  12930.         if (!isset($data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())])) {
  12931.             $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())] = array();
  12932.         }
  12933.         $data['dependencies'][strtolower($pkg->getChannel())][strtolower($pkg->getPackage())][]
  12934.             = $info;
  12935.         if (isset($data['packages'][strtolower($depchannel)][strtolower($dep['name'])])) {
  12936.             $found = false;
  12937.             foreach ($data['packages'][strtolower($depchannel)][strtolower($dep['name'])]
  12938.                   as $i => $p) {
  12939.                 if ($p['channel'] == strtolower($pkg->getChannel()) &&
  12940.                       $p['package'] == strtolower($pkg->getPackage())) {
  12941.                     $found = true;
  12942.                     break;
  12943.                 }
  12944.             }
  12945.             if (!$found) {
  12946.                 $data['packages'][strtolower($depchannel)][strtolower($dep['name'])][]
  12947.                     = array('channel' => strtolower($pkg->getChannel()),
  12948.                             'package' => strtolower($pkg->getPackage()));
  12949.             }
  12950.         } else {
  12951.             if (!isset($data['packages'])) {
  12952.                 $data['packages'] = array();
  12953.             }
  12954.             if (!isset($data['packages'][strtolower($depchannel)])) {
  12955.                 $data['packages'][strtolower($depchannel)] = array();
  12956.             }
  12957.             if (!isset($data['packages'][strtolower($depchannel)][strtolower($dep['name'])])) {
  12958.                 $data['packages'][strtolower($depchannel)][strtolower($dep['name'])] = array();
  12959.             }
  12960.             $data['packages'][strtolower($depchannel)][strtolower($dep['name'])][]
  12961.                 = array('channel' => strtolower($pkg->getChannel()),
  12962.                         'package' => strtolower($pkg->getPackage()));
  12963.         }
  12964.     }
  12965. }
  12966. ?><?php
  12967. /**
  12968.  * PEAR_Downloader, the PEAR Installer's download utility class
  12969.  *
  12970.  * PHP versions 4 and 5
  12971.  *
  12972.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  12973.  * that is available through the world-wide-web at the following URI:
  12974.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  12975.  * the PHP License and are unable to obtain it through the web, please
  12976.  * send a note to license@php.net so we can mail you a copy immediately.
  12977.  *
  12978.  * @category   pear
  12979.  * @package    PEAR
  12980.  * @author     Greg Beaver <cellog@php.net>
  12981.  * @author     Stig Bakken <ssb@php.net>
  12982.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  12983.  * @author     Martin Jansen <mj@php.net>
  12984.  * @copyright  1997-2006 The PHP Group
  12985.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  12986.  * @version    CVS: $Id: Downloader.php,v 1.115 2006/09/24 22:50:44 cellog Exp $
  12987.  * @link       http://pear.php.net/package/PEAR
  12988.  * @since      File available since Release 1.3.0
  12989.  */
  12990.  
  12991. /**
  12992.  * Needed for constants, extending
  12993.  */
  12994. require_once 'phar://go-pear.phar/PEAR/Common.php';
  12995.  
  12996. define('PEAR_INSTALLER_OK',       1);
  12997. define('PEAR_INSTALLER_FAILED',   0);
  12998. define('PEAR_INSTALLER_SKIPPED', -1);
  12999. define('PEAR_INSTALLER_ERROR_NO_PREF_STATE', 2);
  13000.  
  13001. /**
  13002.  * Administration class used to download anything from the internet (PEAR Packages,
  13003.  * static URLs, xml files)
  13004.  *
  13005.  * @category   pear
  13006.  * @package    PEAR
  13007.  * @author     Greg Beaver <cellog@php.net>
  13008.  * @author     Stig Bakken <ssb@php.net>
  13009.  * @author     Tomas V. V. Cox <cox@idecnet.com>
  13010.  * @author     Martin Jansen <mj@php.net>
  13011.  * @copyright  1997-2006 The PHP Group
  13012.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  13013.  * @version    Release: @package_version@
  13014.  * @link       http://pear.php.net/package/PEAR
  13015.  * @since      Class available since Release 1.3.0
  13016.  */
  13017. class PEAR_Downloader extends PEAR_Common
  13018. {
  13019.     /**
  13020.      * @var PEAR_Registry
  13021.      * @access private
  13022.      */
  13023.     var $_registry;
  13024.  
  13025.     /**
  13026.      * @var PEAR_Remote
  13027.      * @access private
  13028.      */
  13029.     var $_remote;
  13030.  
  13031.     /**
  13032.      * Preferred Installation State (snapshot, devel, alpha, beta, stable)
  13033.      * @var string|null
  13034.      * @access private
  13035.      */
  13036.     var $_preferredState;
  13037.  
  13038.     /**
  13039.      * Options from command-line passed to Install.
  13040.      *
  13041.      * Recognized options:<br />
  13042.      *  - onlyreqdeps   : install all required dependencies as well
  13043.      *  - alldeps       : install all dependencies, including optional
  13044.      *  - installroot   : base relative path to install files in
  13045.      *  - force         : force a download even if warnings would prevent it
  13046.      *  - nocompress    : download uncompressed tarballs
  13047.      * @see PEAR_Command_Install
  13048.      * @access private
  13049.      * @var array
  13050.      */
  13051.     var $_options;
  13052.  
  13053.     /**
  13054.      * Downloaded Packages after a call to download().
  13055.      *
  13056.      * Format of each entry:
  13057.      *
  13058.      * <code>
  13059.      * array('pkg' => 'package_name', 'file' => '/path/to/local/file',
  13060.      *    'info' => array() // parsed package.xml
  13061.      * );
  13062.      * </code>
  13063.      * @access private
  13064.      * @var array
  13065.      */
  13066.     var $_downloadedPackages = array();
  13067.  
  13068.     /**
  13069.      * Packages slated for download.
  13070.      *
  13071.      * This is used to prevent downloading a package more than once should it be a dependency
  13072.      * for two packages to be installed.
  13073.      * Format of each entry:
  13074.      *
  13075.      * <pre>
  13076.      * array('package_name1' => parsed package.xml, 'package_name2' => parsed package.xml,
  13077.      * );
  13078.      * </pre>
  13079.      * @access private
  13080.      * @var array
  13081.      */
  13082.     var $_toDownload = array();
  13083.  
  13084.     /**
  13085.      * Array of every package installed, with names lower-cased.
  13086.      *
  13087.      * Format:
  13088.      * <code>
  13089.      * array('package1' => 0, 'package2' => 1, );
  13090.      * </code>
  13091.      * @var array
  13092.      */
  13093.     var $_installed = array();
  13094.  
  13095.     /**
  13096.      * @var array
  13097.      * @access private
  13098.      */
  13099.     var $_errorStack = array();
  13100.     
  13101.     /**
  13102.      * @var boolean
  13103.      * @access private
  13104.      */
  13105.     var $_internalDownload = false;
  13106.  
  13107.     /**
  13108.      * Temporary variable used in sorting packages by dependency in {@link sortPkgDeps()}
  13109.      * @var array
  13110.      * @access private
  13111.      */
  13112.     var $_packageSortTree;
  13113.  
  13114.     /**
  13115.      * Temporary directory, or configuration value where downloads will occur
  13116.      * @var string
  13117.      */
  13118.     var $_downloadDir;
  13119.     // {{{ PEAR_Downloader()
  13120.  
  13121.     /**
  13122.      * @param PEAR_Frontend_*
  13123.      * @param array
  13124.      * @param PEAR_Config
  13125.      */
  13126.     function PEAR_Downloader(&$ui, $options, &$config)
  13127.     {
  13128.         parent::PEAR_Common();
  13129.         $this->_options = $options;
  13130.         $this->config = &$config;
  13131.         $this->_preferredState = $this->config->get('preferred_state');
  13132.         $this->ui = &$ui;
  13133.         if (!$this->_preferredState) {
  13134.             // don't inadvertantly use a non-set preferred_state
  13135.             $this->_preferredState = null;
  13136.         }
  13137.  
  13138.         if (isset($this->_options['installroot'])) {
  13139.             $this->config->setInstallRoot($this->_options['installroot']);
  13140.         }
  13141.         $this->_registry = &$config->getRegistry();
  13142.         $this->_remote = &$config->getRemote();
  13143.  
  13144.         if (isset($this->_options['alldeps']) || isset($this->_options['onlyreqdeps'])) {
  13145.             $this->_installed = $this->_registry->listAllPackages();
  13146.             foreach ($this->_installed as $key => $unused) {
  13147.                 if (!count($unused)) {
  13148.                     continue;
  13149.                 }
  13150.                 $strtolower = create_function('$a','return strtolower($a);');
  13151.                 array_walk($this->_installed[$key], $strtolower);
  13152.             }
  13153.         }
  13154.     }
  13155.  
  13156.     /**
  13157.      * Attempt to discover a channel's remote capabilities from
  13158.      * its server name
  13159.      * @param string
  13160.      * @return boolean
  13161.      */
  13162.     function discover($channel)
  13163.     {
  13164.         $this->log(1, 'Attempting to discover channel "' . $channel . '"...');
  13165.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  13166.         $callback = $this->ui ? array(&$this, '_downloadCallback') : null;
  13167.         if (!class_exists('System')) {
  13168.             require_once 'phar://go-pear.phar/System.php';
  13169.         }
  13170.         $a = $this->downloadHttp('http://' . $channel . '/channel.xml', $this->ui,
  13171.             System::mktemp(array('-d')), $callback, false);
  13172.         PEAR::popErrorHandling();
  13173.         if (PEAR::isError($a)) {
  13174.             return false;
  13175.         }
  13176.         list($a, $lastmodified) = $a;
  13177.         if (!class_exists('PEAR/ChannelFile.php')) {
  13178.             require_once 'phar://go-pear.phar/PEAR/ChannelFile.php';
  13179.         }
  13180.         $b = new PEAR_ChannelFile;
  13181.         if ($b->fromXmlFile($a)) {
  13182.             unlink($a);
  13183.             if ($this->config->get('auto_discover')) {
  13184.                 $this->_registry->addChannel($b, $lastmodified);
  13185.                 $alias = $b->getName();
  13186.                 if ($b->getName() == $this->_registry->channelName($b->getAlias())) {
  13187.                     $alias = $b->getAlias();
  13188.                 }
  13189.                 $this->log(1, 'Auto-discovered channel "' . $channel .
  13190.                     '", alias "' . $alias . '", adding to registry');
  13191.             }
  13192.             return true;
  13193.         }
  13194.         unlink($a);
  13195.         return false;
  13196.     }
  13197.  
  13198.     /**
  13199.      * For simpler unit-testing
  13200.      * @param PEAR_Downloader
  13201.      * @return PEAR_Downloader_Package
  13202.      */
  13203.     function &newDownloaderPackage(&$t)
  13204.     {
  13205.         if (!class_exists('PEAR_Downloader_Package')) {
  13206.             require_once 'phar://go-pear.phar/PEAR/Downloader/Package.php';
  13207.         }
  13208.         $a = &new PEAR_Downloader_Package($t);
  13209.         return $a;
  13210.     }
  13211.  
  13212.     /**
  13213.      * For simpler unit-testing
  13214.      * @param PEAR_Config
  13215.      * @param array
  13216.      * @param array
  13217.      * @param int
  13218.      */
  13219.     function &getDependency2Object(&$c, $i, $p, $s)
  13220.     {
  13221.         if (!class_exists('PEAR/Dependency2.php')) {
  13222.             require_once 'phar://go-pear.phar/PEAR/Dependency2.php';
  13223.         }
  13224.         $z = &new PEAR_Dependency2($c, $i, $p, $s);
  13225.         return $z;
  13226.     }
  13227.  
  13228.     function &download($params)
  13229.     {
  13230.         if (!count($params)) {
  13231.             $a = array();
  13232.             return $a;
  13233.         }
  13234.         if (!isset($this->_registry)) {
  13235.             $this->_registry = &$this->config->getRegistry();
  13236.         }
  13237.         if (!isset($this->_remote)) {
  13238.             $this->_remote = &$this->config->getRemote();
  13239.         }
  13240.         $channelschecked = array();
  13241.         // convert all parameters into PEAR_Downloader_Package objects
  13242.         foreach ($params as $i => $param) {
  13243.             $params[$i] = &$this->newDownloaderPackage($this);
  13244.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13245.             $err = $params[$i]->initialize($param);
  13246.             PEAR::staticPopErrorHandling();
  13247.             if (!$err) {
  13248.                 // skip parameters that were missed by preferred_state
  13249.                 continue;
  13250.             }
  13251.             if (PEAR::isError($err)) {
  13252.                 if (!isset($this->_options['soft'])) {
  13253.                     $this->log(0, $err->getMessage());
  13254.                 }
  13255.                 $params[$i] = false;
  13256.                 if (is_object($param)) {
  13257.                     $param = $param->getChannel() . '/' . $param->getPackage();
  13258.                 }
  13259.                 $this->pushError('Package "' . $param . '" is not valid',
  13260.                     PEAR_INSTALLER_SKIPPED);
  13261.             } else {
  13262.                 do {
  13263.                     if ($params[$i] && $params[$i]->getType() == 'local') {
  13264.                         // bug #7090
  13265.                         // skip channel.xml check for local packages
  13266.                         break;
  13267.                     }
  13268.                     if ($params[$i] && !isset($channelschecked[$params[$i]->getChannel()]) &&
  13269.                           !isset($this->_options['offline'])) {
  13270.                         $channelschecked[$params[$i]->getChannel()] = true;
  13271.                         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13272.                         if (!class_exists('System')) {
  13273.                             require_once 'phar://go-pear.phar/System.php';
  13274.                         }
  13275.                         $curchannel = &$this->_registry->getChannel($params[$i]->getChannel());
  13276.                         if (PEAR::isError($curchannel)) {
  13277.                             PEAR::staticPopErrorHandling();
  13278.                             return $this->raiseError($curchannel);
  13279.                         }
  13280.                         if (PEAR::isError($dir = $this->getDownloadDir())) {
  13281.                             PEAR::staticPopErrorHandling();
  13282.                             break;
  13283.                         }
  13284.                         $a = $this->downloadHttp('http://' . $params[$i]->getChannel() .
  13285.                             '/channel.xml', $this->ui, $dir, null, $curchannel->lastModified());
  13286.  
  13287.                         PEAR::staticPopErrorHandling();
  13288.                         if (PEAR::isError($a) || !$a) {
  13289.                             break;
  13290.                         }
  13291.                         $this->log(0, 'WARNING: channel "' . $params[$i]->getChannel() . '" has ' .
  13292.                             'updated its protocols, use "channel-update ' . $params[$i]->getChannel() .
  13293.                             '" to update');
  13294.                     }
  13295.                 } while (false);
  13296.                 if ($params[$i] && !isset($this->_options['downloadonly'])) {
  13297.                     if (isset($this->_options['packagingroot'])) {
  13298.                         $checkdir = $this->_prependPath(
  13299.                             $this->config->get('php_dir', null, $params[$i]->getChannel()),
  13300.                             $this->_options['packagingroot']);
  13301.                     } else {
  13302.                         $checkdir = $this->config->get('php_dir',
  13303.                             null, $params[$i]->getChannel());
  13304.                     }
  13305.                     while ($checkdir && $checkdir != '/' && !file_exists($checkdir)) {
  13306.                         $checkdir = dirname($checkdir);
  13307.                     }
  13308.                     if ($checkdir == '.') {
  13309.                         $checkdir = '/';
  13310.                     }
  13311.                     if (!is_writeable($checkdir)) {
  13312.                         return PEAR::raiseError('Cannot install, php_dir for channel "' .
  13313.                             $params[$i]->getChannel() . '" is not writeable by the current user');
  13314.                     }
  13315.                 }
  13316.             }
  13317.         }
  13318.         unset($channelschecked);
  13319.         PEAR_Downloader_Package::removeDuplicates($params);
  13320.         if (!count($params)) {
  13321.             $a = array();
  13322.             return $a;
  13323.         }
  13324.         if (!isset($this->_options['nodeps']) && !isset($this->_options['offline'])) {
  13325.             $reverify = true;
  13326.             while ($reverify) {
  13327.                 $reverify = false;
  13328.                 foreach ($params as $i => $param) {
  13329.                     $ret = $params[$i]->detectDependencies($params);
  13330.                     if (PEAR::isError($ret)) {
  13331.                         $reverify = true;
  13332.                         $params[$i] = false;
  13333.                         PEAR_Downloader_Package::removeDuplicates($params);
  13334.                         if (!isset($this->_options['soft'])) {
  13335.                             $this->log(0, $ret->getMessage());
  13336.                         }
  13337.                         continue 2;
  13338.                     }
  13339.                 }
  13340.             }
  13341.         }
  13342.         if (isset($this->_options['offline'])) {
  13343.             $this->log(3, 'Skipping dependency download check, --offline specified');
  13344.         }
  13345.         if (!count($params)) {
  13346.             $a = array();
  13347.             return $a;
  13348.         }
  13349.         while (PEAR_Downloader_Package::mergeDependencies($params));
  13350.         PEAR_Downloader_Package::removeInstalled($params);
  13351.         if (!count($params)) {
  13352.             $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
  13353.             $a = array();
  13354.             return $a;
  13355.         }
  13356.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  13357.         $err = $this->analyzeDependencies($params);
  13358.         PEAR::popErrorHandling();
  13359.         if (!count($params)) {
  13360.             $this->pushError('No valid packages found', PEAR_INSTALLER_FAILED);
  13361.             $a = array();
  13362.             return $a;
  13363.         }
  13364.         $ret = array();
  13365.         $newparams = array();
  13366.         if (isset($this->_options['pretend'])) {
  13367.             return $params;
  13368.         }
  13369.         foreach ($params as $i => $package) {
  13370.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13371.             $pf = &$params[$i]->download();
  13372.             PEAR::staticPopErrorHandling();
  13373.             if (PEAR::isError($pf)) {
  13374.                 if (!isset($this->_options['soft'])) {
  13375.                     $this->log(1, $pf->getMessage());
  13376.                     $this->log(0, 'Error: cannot download "' .
  13377.                         $this->_registry->parsedPackageNameToString($package->getParsedPackage(),
  13378.                             true) .
  13379.                         '"');
  13380.                 }
  13381.                 continue;
  13382.             }
  13383.             $newparams[] = &$params[$i];
  13384.             $ret[] = array('file' => $pf->getArchiveFile(),
  13385.                                    'info' => &$pf,
  13386.                                    'pkg' => $pf->getPackage());
  13387.         }
  13388.         $this->_downloadedPackages = $ret;
  13389.         return $newparams;
  13390.     }
  13391.  
  13392.     /**
  13393.      * @param array all packages to be installed
  13394.      */
  13395.     function analyzeDependencies(&$params)
  13396.     {
  13397.         $hasfailed = $failed = false;
  13398.         if (isset($this->_options['downloadonly'])) {
  13399.             return;
  13400.         }
  13401.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13402.         $redo = true;
  13403.         $reset = false;
  13404.         while ($redo) {
  13405.             $redo = false;
  13406.             foreach ($params as $i => $param) {
  13407.                 $deps = $param->getDeps();
  13408.                 if (!$deps) {
  13409.                     $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
  13410.                         $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
  13411.                     if ($param->getType() == 'xmlrpc') {
  13412.                         $send = $param->getDownloadURL();
  13413.                     } else {
  13414.                         $send = $param->getPackageFile();
  13415.                     }
  13416.                     $installcheck = $depchecker->validatePackage($send, $this, $params);
  13417.                     if (PEAR::isError($installcheck)) {
  13418.                         if (!isset($this->_options['soft'])) {
  13419.                             $this->log(0, $installcheck->getMessage());
  13420.                         }
  13421.                         $hasfailed = true;
  13422.                         $params[$i] = false;
  13423.                         $reset = true;
  13424.                         $redo = true;
  13425.                         $failed = false;
  13426.                         PEAR_Downloader_Package::removeDuplicates($params);
  13427.                         continue 2;
  13428.                     }
  13429.                     continue;
  13430.                 }
  13431.                 if (!$reset && $param->alreadyValidated()) {
  13432.                     continue;
  13433.                 }
  13434.                 if (count($deps)) {
  13435.                     $depchecker = &$this->getDependency2Object($this->config, $this->getOptions(),
  13436.                         $param->getParsedPackage(), PEAR_VALIDATE_DOWNLOADING);
  13437.                     if ($param->getType() == 'xmlrpc') {
  13438.                         $send = $param->getDownloadURL();
  13439.                     } else {
  13440.                         $send = $param->getPackageFile();
  13441.                     }
  13442.                     $installcheck = $depchecker->validatePackage($send, $this, $params);
  13443.                     if (PEAR::isError($installcheck)) {
  13444.                         if (!isset($this->_options['soft'])) {
  13445.                             $this->log(0, $installcheck->getMessage());
  13446.                         }
  13447.                         $hasfailed = true;
  13448.                         $params[$i] = false;
  13449.                         $reset = true;
  13450.                         $redo = true;
  13451.                         $failed = false;
  13452.                         PEAR_Downloader_Package::removeDuplicates($params);
  13453.                         continue 2;
  13454.                     }
  13455.                     $failed = false;
  13456.                     if (isset($deps['required'])) {
  13457.                         foreach ($deps['required'] as $type => $dep) {
  13458.                             // note: Dependency2 will never return a PEAR_Error if ignore-errors
  13459.                             // is specified, so soft is needed to turn off logging
  13460.                             if (!isset($dep[0])) {
  13461.                                 if (PEAR::isError($e = $depchecker->{"validate{$type}Dependency"}($dep,
  13462.                                       true, $params))) {
  13463.                                     $failed = true;
  13464.                                     if (!isset($this->_options['soft'])) {
  13465.                                         $this->log(0, $e->getMessage());
  13466.                                     }
  13467.                                 } elseif (is_array($e) && !$param->alreadyValidated()) {
  13468.                                     if (!isset($this->_options['soft'])) {
  13469.                                         $this->log(0, $e[0]);
  13470.                                     }
  13471.                                 }
  13472.                             } else {
  13473.                                 foreach ($dep as $d) {
  13474.                                     if (PEAR::isError($e =
  13475.                                           $depchecker->{"validate{$type}Dependency"}($d,
  13476.                                           true, $params))) {
  13477.                                         $failed = true;
  13478.                                         if (!isset($this->_options['soft'])) {
  13479.                                             $this->log(0, $e->getMessage());
  13480.                                         }
  13481.                                     } elseif (is_array($e) && !$param->alreadyValidated()) {
  13482.                                         if (!isset($this->_options['soft'])) {
  13483.                                             $this->log(0, $e[0]);
  13484.                                         }
  13485.                                     }
  13486.                                 }
  13487.                             }
  13488.                         }
  13489.                         if (isset($deps['optional'])) {
  13490.                             foreach ($deps['optional'] as $type => $dep) {
  13491.                                 if (!isset($dep[0])) {
  13492.                                     if (PEAR::isError($e =
  13493.                                           $depchecker->{"validate{$type}Dependency"}($dep,
  13494.                                           false, $params))) {
  13495.                                         $failed = true;
  13496.                                         if (!isset($this->_options['soft'])) {
  13497.                                             $this->log(0, $e->getMessage());
  13498.                                         }
  13499.                                     } elseif (is_array($e) && !$param->alreadyValidated()) {
  13500.                                         if (!isset($this->_options['soft'])) {
  13501.                                             $this->log(0, $e[0]);
  13502.                                         }
  13503.                                     }
  13504.                                 } else {
  13505.                                     foreach ($dep as $d) {
  13506.                                         if (PEAR::isError($e =
  13507.                                               $depchecker->{"validate{$type}Dependency"}($d,
  13508.                                               false, $params))) {
  13509.                                             $failed = true;
  13510.                                             if (!isset($this->_options['soft'])) {
  13511.                                                 $this->log(0, $e->getMessage());
  13512.                                             }
  13513.                                         } elseif (is_array($e) && !$param->alreadyValidated()) {
  13514.                                             if (!isset($this->_options['soft'])) {
  13515.                                                 $this->log(0, $e[0]);
  13516.                                             }
  13517.                                         }
  13518.                                     }
  13519.                                 }
  13520.                             }
  13521.                         }
  13522.                         $groupname = $param->getGroup();
  13523.                         if (isset($deps['group']) && $groupname) {
  13524.                             if (!isset($deps['group'][0])) {
  13525.                                 $deps['group'] = array($deps['group']);
  13526.                             }
  13527.                             $found = false;
  13528.                             foreach ($deps['group'] as $group) {
  13529.                                 if ($group['attribs']['name'] == $groupname) {
  13530.                                     $found = true;
  13531.                                     break;
  13532.                                 }
  13533.                             }
  13534.                             if ($found) {
  13535.                                 unset($group['attribs']);
  13536.                                 foreach ($group as $type => $dep) {
  13537.                                     if (!isset($dep[0])) {
  13538.                                         if (PEAR::isError($e =
  13539.                                               $depchecker->{"validate{$type}Dependency"}($dep,
  13540.                                               false, $params))) {
  13541.                                             $failed = true;
  13542.                                             if (!isset($this->_options['soft'])) {
  13543.                                                 $this->log(0, $e->getMessage());
  13544.                                             }
  13545.                                         } elseif (is_array($e) && !$param->alreadyValidated()) {
  13546.                                             if (!isset($this->_options['soft'])) {
  13547.                                                 $this->log(0, $e[0]);
  13548.                                             }
  13549.                                         }
  13550.                                     } else {
  13551.                                         foreach ($dep as $d) {
  13552.                                             if (PEAR::isError($e =
  13553.                                                   $depchecker->{"validate{$type}Dependency"}($d,
  13554.                                                   false, $params))) {
  13555.                                                 $failed = true;
  13556.                                                 if (!isset($this->_options['soft'])) {
  13557.                                                     $this->log(0, $e->getMessage());
  13558.                                                 }
  13559.                                             } elseif (is_array($e) && !$param->alreadyValidated()) {
  13560.                                                 if (!isset($this->_options['soft'])) {
  13561.                                                     $this->log(0, $e[0]);
  13562.                                                 }
  13563.                                             }
  13564.                                         }
  13565.                                     }
  13566.                                 }
  13567.                             }
  13568.                         }
  13569.                     } else {
  13570.                         foreach ($deps as $dep) {
  13571.                             if (PEAR::isError($e = $depchecker->validateDependency1($dep, $params))) {
  13572.                                 $failed = true;
  13573.                                 if (!isset($this->_options['soft'])) {
  13574.                                     $this->log(0, $e->getMessage());
  13575.                                 }
  13576.                             } elseif (is_array($e) && !$param->alreadyValidated()) {
  13577.                                 if (!isset($this->_options['soft'])) {
  13578.                                     $this->log(0, $e[0]);
  13579.                                 }
  13580.                             }
  13581.                         }
  13582.                     }
  13583.                     $params[$i]->setValidated();
  13584.                 }
  13585.                 if ($failed) {
  13586.                     $hasfailed = true;
  13587.                     $params[$i] = false;
  13588.                     $reset = true;
  13589.                     $redo = true;
  13590.                     $failed = false;
  13591.                     PEAR_Downloader_Package::removeDuplicates($params);
  13592.                     continue 2;
  13593.                 }
  13594.             }
  13595.         }
  13596.         PEAR::staticPopErrorHandling();
  13597.         if ($hasfailed && (isset($this->_options['ignore-errors']) ||
  13598.               isset($this->_options['nodeps']))) {
  13599.             // this is probably not needed, but just in case
  13600.             if (!isset($this->_options['soft'])) {
  13601.                 $this->log(0, 'WARNING: dependencies failed');
  13602.             }
  13603.         }
  13604.     }
  13605.  
  13606.     /**
  13607.      * Retrieve the directory that downloads will happen in
  13608.      * @access private
  13609.      * @return string
  13610.      */
  13611.     function getDownloadDir()
  13612.     {
  13613.         if (isset($this->_downloadDir)) {
  13614.             return $this->_downloadDir;
  13615.         }
  13616.         $downloaddir = $this->config->get('download_dir');
  13617.         if (empty($downloaddir)) {
  13618.             if (!class_exists('System')) {
  13619.                 require_once 'phar://go-pear.phar/System.php';
  13620.             }
  13621.             if (PEAR::isError($downloaddir = System::mktemp('-d'))) {
  13622.                 return $downloaddir;
  13623.             }
  13624.             $this->log(3, '+ tmp dir created at ' . $downloaddir);
  13625.         }
  13626.         if (!is_writable($downloaddir)) {
  13627.             if (PEAR::isError(System::mkdir(array('-p', $downloaddir)))) {
  13628.                 return PEAR::raiseError('download directory "' . $downloaddir .
  13629.                     '" is not writeable.  Change download_dir config variable to ' .
  13630.                     'a writeable dir');
  13631.             }
  13632.         }
  13633.         return $this->_downloadDir = $downloaddir;
  13634.     }
  13635.  
  13636.     function setDownloadDir($dir)
  13637.     {
  13638.         $this->_downloadDir = $dir;
  13639.     }
  13640.  
  13641.     // }}}
  13642.     // {{{ configSet()
  13643.     function configSet($key, $value, $layer = 'user', $channel = false)
  13644.     {
  13645.         $this->config->set($key, $value, $layer, $channel);
  13646.         $this->_preferredState = $this->config->get('preferred_state', null, $channel);
  13647.         if (!$this->_preferredState) {
  13648.             // don't inadvertantly use a non-set preferred_state
  13649.             $this->_preferredState = null;
  13650.         }
  13651.     }
  13652.  
  13653.     // }}}
  13654.     // {{{ setOptions()
  13655.     function setOptions($options)
  13656.     {
  13657.         $this->_options = $options;
  13658.     }
  13659.  
  13660.     // }}}
  13661.     // {{{ setOptions()
  13662.     function getOptions()
  13663.     {
  13664.         return $this->_options;
  13665.     }
  13666.  
  13667.     // }}}
  13668.  
  13669.     /**
  13670.      * For simpler unit-testing
  13671.      * @param PEAR_Config
  13672.      * @param int
  13673.      * @param string
  13674.      */
  13675.     function &getPackagefileObject(&$c, $d, $t = false)
  13676.     {
  13677.         if (!class_exists('PEAR_PackageFile')) {
  13678.             require_once 'phar://go-pear.phar/PEAR/PackageFile.php';
  13679.         }
  13680.         $a = &new PEAR_PackageFile($c, $d, $t);
  13681.         return $a;
  13682.     }
  13683.  
  13684.     // {{{ _getPackageDownloadUrl()
  13685.  
  13686.     /**
  13687.      * @param array output of {@link parsePackageName()}
  13688.      * @access private
  13689.      */
  13690.     function _getPackageDownloadUrl($parr)
  13691.     {
  13692.         $curchannel = $this->config->get('default_channel');
  13693.         $this->configSet('default_channel', $parr['channel']);
  13694.         // getDownloadURL returns an array.  On error, it only contains information
  13695.         // on the latest release as array(version, info).  On success it contains
  13696.         // array(version, info, download url string)
  13697.         $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
  13698.         if (!$this->_registry->channelExists($parr['channel'])) {
  13699.             do {
  13700.                 if ($this->config->get('auto_discover')) {
  13701.                     if ($this->discover($parr['channel'])) {
  13702.                         break;
  13703.                     }
  13704.                 }
  13705.                 $this->configSet('default_channel', $curchannel);
  13706.                 return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
  13707.             } while (false);
  13708.         }
  13709.         $chan = &$this->_registry->getChannel($parr['channel']);
  13710.         if (PEAR::isError($chan)) {
  13711.             return $chan;
  13712.         }
  13713.         $version = $this->_registry->packageInfo($parr['package'], 'version',
  13714.             $parr['channel']);
  13715.         if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  13716.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  13717.             $rest = &$this->config->getREST('1.0', $this->_options);
  13718.             if (!isset($parr['version']) && !isset($parr['state']) && $version
  13719.                   && !isset($this->_options['downloadonly'])) {
  13720.                 $url = $rest->getDownloadURL($base, $parr, $state, $version);
  13721.             } else {
  13722.                 $url = $rest->getDownloadURL($base, $parr, $state, false);
  13723.             }
  13724.             if (PEAR::isError($url)) {
  13725.                 $this->configSet('default_channel', $curchannel);
  13726.                 return $url;
  13727.             }
  13728.             if ($parr['channel'] != $curchannel) {
  13729.                 $this->configSet('default_channel', $curchannel);
  13730.             }
  13731.             if (!is_array($url)) {
  13732.                 return $url;
  13733.             }
  13734.             $url['raw'] = false; // no checking is necessary for REST
  13735.             if (!is_array($url['info'])) {
  13736.                 return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
  13737.                     'this should never happen');
  13738.             }
  13739.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13740.             $testversion = $this->_registry->packageInfo($url['package'], 'version',
  13741.                 $parr['channel']);
  13742.             PEAR::staticPopErrorHandling();
  13743.             if (!isset($this->_options['force']) &&
  13744.                   !isset($this->_options['downloadonly']) &&
  13745.                   !PEAR::isError($testversion)) {
  13746.                 if (version_compare($testversion, $url['version'], '>=')) {
  13747.                     return PEAR::raiseError($this->_registry->parsedPackageNameToString(
  13748.                         $parr, true) . ' is already installed and is newer than detected ' .
  13749.                         'release version ' . $url['version'], -976);
  13750.                 }
  13751.             }
  13752.             if (isset($url['info']['required']) || $url['compatible']) {
  13753.                 require_once 'phar://go-pear.phar/PEAR/PackageFile/v2.php';
  13754.                 $pf = new PEAR_PackageFile_v2;
  13755.                 $pf->setRawChannel($parr['channel']);
  13756.                 if ($url['compatible']) {
  13757.                     $pf->setRawCompatible($url['compatible']);
  13758.                 }
  13759.             } else {
  13760.                 require_once 'phar://go-pear.phar/PEAR/PackageFile/v1.php';
  13761.                 $pf = new PEAR_PackageFile_v1;
  13762.             }
  13763.             $pf->setRawPackage($url['package']);
  13764.             $pf->setDeps($url['info']);
  13765.             $pf->setRawState($url['stability']);
  13766.             $url['info'] = &$pf;
  13767.             if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  13768.                 $ext = '.tar';
  13769.             } else {
  13770.                 $ext = '.tgz';
  13771.             }
  13772.             if (is_array($url)) {
  13773.                 if (isset($url['url'])) {
  13774.                     $url['url'] .= $ext;
  13775.                 }
  13776.             }
  13777.             return $url;
  13778.         } elseif ($chan->supports('xmlrpc', 'package.getDownloadURL', false, '1.1')) {
  13779.             // don't install with the old version information unless we're doing a plain
  13780.             // vanilla simple installation.  If the user says to install a particular
  13781.             // version or state, ignore the current installed version
  13782.             if (!isset($parr['version']) && !isset($parr['state']) && $version
  13783.                   && !isset($this->_options['downloadonly'])) {
  13784.                 $url = $this->_remote->call('package.getDownloadURL', $parr, $state, $version);
  13785.             } else {
  13786.                 $url = $this->_remote->call('package.getDownloadURL', $parr, $state);
  13787.             }
  13788.         } else {
  13789.             $url = $this->_remote->call('package.getDownloadURL', $parr, $state);
  13790.         }
  13791.         if (PEAR::isError($url)) {
  13792.             return $url;
  13793.         }
  13794.         if ($parr['channel'] != $curchannel) {
  13795.             $this->configSet('default_channel', $curchannel);
  13796.         }
  13797.         if (isset($url['__PEAR_ERROR_CLASS__'])) {
  13798.             return PEAR::raiseError($url['message']);
  13799.         }
  13800.         if (!is_array($url)) {
  13801.             return $url;
  13802.         }
  13803.         $url['raw'] = $url['info'];
  13804.         if (isset($this->_options['downloadonly'])) {
  13805.             $pkg = &$this->getPackagefileObject($this->config, $this->debug);
  13806.         } else {
  13807.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13808.             if (PEAR::isError($dir = $this->getDownloadDir())) {
  13809.                 PEAR::staticPopErrorHandling();
  13810.                 return $dir;
  13811.             }
  13812.             PEAR::staticPopErrorHandling();
  13813.             $pkg = &$this->getPackagefileObject($this->config, $this->debug, $dir);
  13814.         }
  13815.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13816.         $pinfo = &$pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote');
  13817.         PEAR::staticPopErrorHandling();
  13818.         if (PEAR::isError($pinfo)) {
  13819.             if (!isset($this->_options['soft'])) {
  13820.                 $this->log(0, $pinfo->getMessage());
  13821.             }
  13822.             return PEAR::raiseError('Remote package.xml is not valid - this should never happen');
  13823.         }
  13824.         $url['info'] = &$pinfo;
  13825.         if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  13826.             $ext = '.tar';
  13827.         } else {
  13828.             $ext = '.tgz';
  13829.         }
  13830.         if (is_array($url)) {
  13831.             if (isset($url['url'])) {
  13832.                 $url['url'] .= $ext;
  13833.             }
  13834.         }
  13835.         return $url;
  13836.     }
  13837.     // }}}
  13838.     // {{{ getDepPackageDownloadUrl()
  13839.  
  13840.     /**
  13841.      * @param array dependency array
  13842.      * @access private
  13843.      */
  13844.     function _getDepPackageDownloadUrl($dep, $parr)
  13845.     {
  13846.         $xsdversion = isset($dep['rel']) ? '1.0' : '2.0';
  13847.         $curchannel = $this->config->get('default_channel');
  13848.         if (isset($dep['uri'])) {
  13849.             $xsdversion = '2.0';
  13850.             $chan = &$this->_registry->getChannel('__uri');
  13851.             if (PEAR::isError($chan)) {
  13852.                 return $chan;
  13853.             }
  13854.             $version = $this->_registry->packageInfo($dep['name'], 'version', '__uri');
  13855.             $this->configSet('default_channel', '__uri');
  13856.         } else {
  13857.             if (isset($dep['channel'])) {
  13858.                 $remotechannel = $dep['channel'];
  13859.             } else {
  13860.                 $remotechannel = 'pear.php.net';
  13861.             }
  13862.             if (!$this->_registry->channelExists($remotechannel)) {
  13863.                 do {
  13864.                     if ($this->config->get('auto_discover')) {
  13865.                         if ($this->discover($remotechannel)) {
  13866.                             break;
  13867.                         }
  13868.                     }
  13869.                     return PEAR::raiseError('Unknown remote channel: ' . $remotechannel);
  13870.                 } while (false);
  13871.             }
  13872.             $chan = &$this->_registry->getChannel($remotechannel);
  13873.             if (PEAR::isError($chan)) {
  13874.                 return $chan;
  13875.             }
  13876.             $version = $this->_registry->packageInfo($dep['name'], 'version',
  13877.                 $remotechannel);
  13878.             $this->configSet('default_channel', $remotechannel);
  13879.         }
  13880.         $state = isset($parr['state']) ? $parr['state'] : $this->config->get('preferred_state');
  13881.         if (isset($parr['state']) && isset($parr['version'])) {
  13882.             unset($parr['state']);
  13883.         }
  13884.         if (isset($dep['uri'])) {
  13885.             $info = &$this->newDownloaderPackage($this);
  13886.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13887.             $err = $info->initialize($dep);
  13888.             PEAR::staticPopErrorHandling();
  13889.             if (!$err) {
  13890.                 // skip parameters that were missed by preferred_state
  13891.                 return PEAR::raiseError('Cannot initialize dependency');
  13892.             }
  13893.             if (PEAR::isError($err)) {
  13894.                 if (!isset($this->_options['soft'])) {
  13895.                     $this->log(0, $err->getMessage());
  13896.                 }
  13897.                 if (is_object($info)) {
  13898.                     $param = $info->getChannel() . '/' . $info->getPackage();
  13899.                 }
  13900.                 return PEAR::raiseError('Package "' . $param . '" is not valid');
  13901.             }
  13902.             return $info;
  13903.         } elseif ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  13904.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  13905.             $rest = &$this->config->getREST('1.0', $this->_options);
  13906.             $url = $rest->getDepDownloadURL($base, $xsdversion, $dep, $parr,
  13907.                     $state, $version);
  13908.             if (PEAR::isError($url)) {
  13909.                 return $url;
  13910.             }
  13911.             if ($parr['channel'] != $curchannel) {
  13912.                 $this->configSet('default_channel', $curchannel);
  13913.             }
  13914.             if (!is_array($url)) {
  13915.                 return $url;
  13916.             }
  13917.             $url['raw'] = false; // no checking is necessary for REST
  13918.             if (!is_array($url['info'])) {
  13919.                 return PEAR::raiseError('Invalid remote dependencies retrieved from REST - ' .
  13920.                     'this should never happen');
  13921.             }
  13922.             if (isset($url['info']['required'])) {
  13923.                 if (!class_exists('PEAR_PackageFile_v2')) {
  13924.                     require_once 'phar://go-pear.phar/PEAR/PackageFile/v2.php';
  13925.                 }
  13926.                 $pf = new PEAR_PackageFile_v2;
  13927.                 $pf->setRawChannel($remotechannel);
  13928.             } else {
  13929.                 if (!class_exists('PEAR_PackageFile_v1')) {
  13930.                     require_once 'phar://go-pear.phar/PEAR/PackageFile/v1.php';
  13931.                 }
  13932.                 $pf = new PEAR_PackageFile_v1;
  13933.             }
  13934.             $pf->setRawPackage($url['package']);
  13935.             $pf->setDeps($url['info']);
  13936.             $pf->setRawState($url['stability']);
  13937.             $url['info'] = &$pf;
  13938.             if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  13939.                 $ext = '.tar';
  13940.             } else {
  13941.                 $ext = '.tgz';
  13942.             }
  13943.             if (is_array($url)) {
  13944.                 if (isset($url['url'])) {
  13945.                     $url['url'] .= $ext;
  13946.                 }
  13947.             }
  13948.             return $url;
  13949.         } elseif ($chan->supports('xmlrpc', 'package.getDepDownloadURL', false, '1.1')) {
  13950.             if ($version) {
  13951.                 $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr,
  13952.                     $state, $version);
  13953.             } else {
  13954.                 $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr,
  13955.                     $state);
  13956.             }
  13957.         } else {
  13958.             $url = $this->_remote->call('package.getDepDownloadURL', $xsdversion, $dep, $parr, $state);
  13959.         }
  13960.         if ($this->config->get('default_channel') != $curchannel) {
  13961.             $this->configSet('default_channel', $curchannel);
  13962.         }
  13963.         if (!is_array($url)) {
  13964.             return $url;
  13965.         }
  13966.         if (isset($url['__PEAR_ERROR_CLASS__'])) {
  13967.             return PEAR::raiseError($url['message']);
  13968.         }
  13969.         $url['raw'] = $url['info'];
  13970.         $pkg = &$this->getPackagefileObject($this->config, $this->debug);
  13971.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  13972.         $pinfo = &$pkg->fromXmlString($url['info'], PEAR_VALIDATE_DOWNLOADING, 'remote');
  13973.         PEAR::staticPopErrorHandling();
  13974.         if (PEAR::isError($pinfo)) {
  13975.             if (!isset($this->_options['soft'])) {
  13976.                 $this->log(0, $pinfo->getMessage());
  13977.             }
  13978.             return PEAR::raiseError('Remote package.xml is not valid - this should never happen');
  13979.         }
  13980.         $url['info'] = &$pinfo;
  13981.         if (is_array($url)) {
  13982.             if (!extension_loaded("zlib") || isset($this->_options['nocompress'])) {
  13983.                 $ext = '.tar';
  13984.             } else {
  13985.                 $ext = '.tgz';
  13986.             }
  13987.             if (isset($url['url'])) {
  13988.                 $url['url'] .= $ext;
  13989.             }
  13990.         }
  13991.         return $url;
  13992.     }
  13993.     // }}}
  13994.     // {{{ getPackageDownloadUrl()
  13995.  
  13996.     /**
  13997.      * @deprecated in favor of _getPackageDownloadUrl
  13998.      */
  13999.     function getPackageDownloadUrl($package, $version = null, $channel = false)
  14000.     {
  14001.         if ($version) {
  14002.             $package .= "-$version";
  14003.         }
  14004.         if ($this === null || $this->_registry === null) {
  14005.             $package = "http://pear.php.net/get/$package";
  14006.         } else {
  14007.             $chan = $this->_registry->getChannel($channel);
  14008.             if (PEAR::isError($chan)) {
  14009.                 return '';
  14010.             }
  14011.             $package = "http://" . $chan->getServer() . "/get/$package";
  14012.         }
  14013.         if (!extension_loaded("zlib")) {
  14014.             $package .= '?uncompress=yes';
  14015.         }
  14016.         return $package;
  14017.     }
  14018.  
  14019.     // }}}
  14020.     // {{{ getDownloadedPackages()
  14021.  
  14022.     /**
  14023.      * Retrieve a list of downloaded packages after a call to {@link download()}.
  14024.      *
  14025.      * Also resets the list of downloaded packages.
  14026.      * @return array
  14027.      */
  14028.     function getDownloadedPackages()
  14029.     {
  14030.         $ret = $this->_downloadedPackages;
  14031.         $this->_downloadedPackages = array();
  14032.         $this->_toDownload = array();
  14033.         return $ret;
  14034.     }
  14035.  
  14036.     // }}}
  14037.     // {{{ _downloadCallback()
  14038.  
  14039.     function _downloadCallback($msg, $params = null)
  14040.     {
  14041.         switch ($msg) {
  14042.             case 'saveas':
  14043.                 $this->log(1, "downloading $params ...");
  14044.                 break;
  14045.             case 'done':
  14046.                 $this->log(1, '...done: ' . number_format($params, 0, '', ',') . ' bytes');
  14047.                 break;
  14048.             case 'bytesread':
  14049.                 static $bytes;
  14050.                 if (empty($bytes)) {
  14051.                     $bytes = 0;
  14052.                 }
  14053.                 if (!($bytes % 10240)) {
  14054.                     $this->log(1, '.', false);
  14055.                 }
  14056.                 $bytes += $params;
  14057.                 break;
  14058.             case 'start':
  14059.                 if($params[1] == -1) {
  14060.                     $length = "Unknown size";
  14061.                 } else {
  14062.                     $length = number_format($params[1], 0, '', ',')." bytes";
  14063.                 }
  14064.                 $this->log(1, "Starting to download {$params[0]} ($length)");
  14065.                 break;
  14066.         }
  14067.         if (method_exists($this->ui, '_downloadCallback'))
  14068.             $this->ui->_downloadCallback($msg, $params);
  14069.     }
  14070.  
  14071.     // }}}
  14072.     // {{{ _prependPath($path, $prepend)
  14073.  
  14074.     function _prependPath($path, $prepend)
  14075.     {
  14076.         if (strlen($prepend) > 0) {
  14077.             if (OS_WINDOWS && preg_match('/^[a-z]:/i', $path)) {
  14078.                 if (preg_match('/^[a-z]:/i', $prepend)) {
  14079.                     $prepend = substr($prepend, 2);
  14080.                 } elseif ($prepend{0} != '\\') {
  14081.                     $prepend = "\\$prepend";
  14082.                 }
  14083.                 $path = substr($path, 0, 2) . $prepend . substr($path, 2);
  14084.             } else {
  14085.                 $path = $prepend . $path;
  14086.             }
  14087.         }
  14088.         return $path;
  14089.     }
  14090.     // }}}
  14091.     // {{{ pushError($errmsg, $code)
  14092.  
  14093.     /**
  14094.      * @param string
  14095.      * @param integer
  14096.      */
  14097.     function pushError($errmsg, $code = -1)
  14098.     {
  14099.         array_push($this->_errorStack, array($errmsg, $code));
  14100.     }
  14101.  
  14102.     // }}}
  14103.     // {{{ getErrorMsgs()
  14104.  
  14105.     function getErrorMsgs()
  14106.     {
  14107.         $msgs = array();
  14108.         $errs = $this->_errorStack;
  14109.         foreach ($errs as $err) {
  14110.             $msgs[] = $err[0];
  14111.         }
  14112.         $this->_errorStack = array();
  14113.         return $msgs;
  14114.     }
  14115.  
  14116.     // }}}
  14117.  
  14118.     /**
  14119.      * for BC
  14120.      */
  14121.     function sortPkgDeps(&$packages, $uninstall = false)
  14122.     {
  14123.         $uninstall ? 
  14124.             $this->sortPackagesForUninstall($packages) :
  14125.             $this->sortPackagesForInstall($packages);
  14126.     }
  14127.  
  14128.     function _getDepTreeDP($package, $packages, &$deps, &$checked)
  14129.     {
  14130.         $pf = $package->getPackageFile();
  14131.         if (!is_array($checked)) {
  14132.             $checked = array();
  14133.         }
  14134.         if (!isset($checked[strtolower($package->getChannel())])) {
  14135.             $checked[strtolower($package->getChannel())] = array();
  14136.         }
  14137.         if (!isset($checked[strtolower($package->getChannel())][strtolower($package->getPackage())])) {
  14138.             $checked[strtolower($package->getChannel())][strtolower($package->getPackage())] = array();
  14139.         }
  14140.         $checked[strtolower($package->getChannel())][strtolower($package->getPackage())]
  14141.             = true;
  14142.         $pdeps = $pf->getDeps(true);
  14143.         if (!$pdeps) {
  14144.             return;
  14145.         }
  14146.         if ($pf->getPackagexmlVersion() == '1.0') {
  14147.             foreach ($pdeps as $dep) {
  14148.                 if ($dep['type'] != 'pkg') {
  14149.                     continue;
  14150.                 }
  14151.                 $deps['pear.php.net'][strtolower($dep['name'])] = true;
  14152.                 foreach ($packages as $p) {
  14153.                     $dep['channel'] = 'pear.php.net';
  14154.                     $dep['package'] = $dep['name'];
  14155.                     if ($p->isEqual($dep)) {
  14156.                         if (!isset($checked[strtolower($p->getChannel())]
  14157.                               [strtolower($p->getPackage())])) {
  14158.                             // add the dependency's dependencies to the tree
  14159.                             $this->_getDepTreeDP($p, $packages, $deps, $checked);
  14160.                         }
  14161.                     }
  14162.                 }
  14163.             }
  14164.         } else {
  14165.             $tdeps = array();
  14166.             if (isset($pdeps['required']['package'])) {
  14167.                 $t = $pdeps['required']['package'];
  14168.                 if (!isset($t[0])) {
  14169.                     $t = array($t);
  14170.                 }
  14171.                 $tdeps = array_merge($tdeps, $t);
  14172.             }
  14173.             if (isset($pdeps['required']['subpackage'])) {
  14174.                 $t = $pdeps['required']['subpackage'];
  14175.                 if (!isset($t[0])) {
  14176.                     $t = array($t);
  14177.                 }
  14178.                 $tdeps = array_merge($tdeps, $t);
  14179.             }
  14180.             if (isset($pdeps['optional']['package'])) {
  14181.                 $t = $pdeps['optional']['package'];
  14182.                 if (!isset($t[0])) {
  14183.                     $t = array($t);
  14184.                 }
  14185.                 $tdeps = array_merge($tdeps, $t);
  14186.             }
  14187.             if (isset($pdeps['optional']['subpackage'])) {
  14188.                 $t = $pdeps['optional']['subpackage'];
  14189.                 if (!isset($t[0])) {
  14190.                     $t = array($t);
  14191.                 }
  14192.                 $tdeps = array_merge($tdeps, $t);
  14193.             }
  14194.             if (isset($pdeps['group'])) {
  14195.                 if (!isset($pdeps['group'][0])) {
  14196.                     $pdeps['group'] = array($pdeps['group']);
  14197.                 }
  14198.                 foreach ($pdeps['group'] as $group) {
  14199.                     if (isset($group['package'])) {
  14200.                         $t = $group['package'];
  14201.                         if (!isset($t[0])) {
  14202.                             $t = array($t);
  14203.                         }
  14204.                         $tdeps = array_merge($tdeps, $t);
  14205.                     }
  14206.                     if (isset($group['subpackage'])) {
  14207.                         $t = $group['subpackage'];
  14208.                         if (!isset($t[0])) {
  14209.                             $t = array($t);
  14210.                         }
  14211.                         $tdeps = array_merge($tdeps, $t);
  14212.                     }
  14213.                 }
  14214.             }
  14215.             foreach ($tdeps as $dep) {
  14216.                 if (!isset($dep['channel'])) {
  14217.                     $depchannel = '__uri';
  14218.                 } else {
  14219.                     $depchannel = $dep['channel'];
  14220.                 }
  14221.                 if (!is_array($deps)) {
  14222.                     $deps = array();
  14223.                 }
  14224.                 if (!isset($deps[$depchannel])) {
  14225.                     $deps[$depchannel] = array();
  14226.                 }
  14227.                 $deps[$depchannel][strtolower($dep['name'])] = true;
  14228.                 foreach ($packages as $p) {
  14229.                     $dep['channel'] = $depchannel;
  14230.                     $dep['package'] = $dep['name'];
  14231.                     if ($p->isEqual($dep)) {
  14232.                         if (!isset($checked[strtolower($p->getChannel())]
  14233.                               [strtolower($p->getPackage())])) {
  14234.                             // add the dependency's dependencies to the tree
  14235.                             $this->_getDepTreeDP($p, $packages, $deps, $checked);
  14236.                         }
  14237.                     }
  14238.                 }
  14239.             }
  14240.         }
  14241.     }
  14242.  
  14243.     /**
  14244.      * Sort a list of arrays of array(downloaded packagefilename) by dependency.
  14245.      *
  14246.      * It also removes duplicate dependencies
  14247.      * @param array an array of downloaded PEAR_Downloader_Packages
  14248.      * @return array array of array(packagefilename, package.xml contents)
  14249.      */
  14250.     function sortPackagesForInstall(&$packages)
  14251.     {
  14252.         foreach ($packages as $i => $package) {
  14253.             $checked = $deps = array();
  14254.             $this->_getDepTreeDP($packages[$i], $packages, $deps, $checked);
  14255.             if (!isset($this->_depTree)) {
  14256.                 $this->_depTree = array();
  14257.             }
  14258.             if (!isset($this->_depTree[$package->getChannel()])) {
  14259.                 $this->_depTree[$package->getChannel()] = array();
  14260.             }
  14261.             $this->_depTree[$package->getChannel()][$package->getPackage()] = $deps;
  14262.         }
  14263.         usort($packages, array(&$this, '_sortInstall'));
  14264.     }
  14265.  
  14266.     function _dependsOn($a, $b)
  14267.     {
  14268.         return $this->_checkDepTree(strtolower($a->getChannel()), strtolower($a->getPackage()),
  14269.             $b);
  14270.     }
  14271.  
  14272.     function _checkDepTree($channel, $package, $b, $checked = array())
  14273.     {
  14274.         $checked[$channel][$package] = true;
  14275.         if (!isset($this->_depTree[$channel][$package])) {
  14276.             return false;
  14277.         }
  14278.         if (isset($this->_depTree[$channel][$package][strtolower($b->getChannel())]
  14279.               [strtolower($b->getPackage())])) {
  14280.             return true;
  14281.         }
  14282.         foreach ($this->_depTree[$channel][$package] as $ch => $packages) {
  14283.             foreach ($packages as $pa => $true) {
  14284.                 if ($this->_checkDepTree($ch, $pa, $b, $checked)) {
  14285.                     return true;
  14286.                 }
  14287.             }
  14288.         }
  14289.         return false;
  14290.     }
  14291.  
  14292.     function _sortInstall($a, $b)
  14293.     {
  14294.         if (!$a->getDeps() && !$b->getDeps()) {
  14295.             return 0; // neither package has dependencies, order is insignificant
  14296.         }
  14297.         if ($a->getDeps() && !$b->getDeps()) {
  14298.             return 1; // $a must be installed after $b because $a has dependencies
  14299.         }
  14300.         if (!$a->getDeps() && $b->getDeps()) {
  14301.             return -1; // $b must be installed after $a because $b has dependencies
  14302.         }
  14303.         // both packages have dependencies
  14304.         if ($this->_dependsOn($a, $b)) {
  14305.             return 1;
  14306.         }
  14307.         if ($this->_dependsOn($b, $a)) {
  14308.             return -1;
  14309.         }
  14310.         return 0;
  14311.     }
  14312.  
  14313.     /**
  14314.      * Download a file through HTTP.  Considers suggested file name in
  14315.      * Content-disposition: header and can run a callback function for
  14316.      * different events.  The callback will be called with two
  14317.      * parameters: the callback type, and parameters.  The implemented
  14318.      * callback types are:
  14319.      *
  14320.      *  'setup'       called at the very beginning, parameter is a UI object
  14321.      *                that should be used for all output
  14322.      *  'message'     the parameter is a string with an informational message
  14323.      *  'saveas'      may be used to save with a different file name, the
  14324.      *                parameter is the filename that is about to be used.
  14325.      *                If a 'saveas' callback returns a non-empty string,
  14326.      *                that file name will be used as the filename instead.
  14327.      *                Note that $save_dir will not be affected by this, only
  14328.      *                the basename of the file.
  14329.      *  'start'       download is starting, parameter is number of bytes
  14330.      *                that are expected, or -1 if unknown
  14331.      *  'bytesread'   parameter is the number of bytes read so far
  14332.      *  'done'        download is complete, parameter is the total number
  14333.      *                of bytes read
  14334.      *  'connfailed'  if the TCP/SSL connection fails, this callback is called
  14335.      *                with array(host,port,errno,errmsg)
  14336.      *  'writefailed' if writing to disk fails, this callback is called
  14337.      *                with array(destfile,errmsg)
  14338.      *
  14339.      * If an HTTP proxy has been configured (http_proxy PEAR_Config
  14340.      * setting), the proxy will be used.
  14341.      *
  14342.      * @param string  $url       the URL to download
  14343.      * @param object  $ui        PEAR_Frontend_* instance
  14344.      * @param object  $config    PEAR_Config instance
  14345.      * @param string  $save_dir  directory to save file in
  14346.      * @param mixed   $callback  function/method to call for status
  14347.      *                           updates
  14348.      * @param false|string|array $lastmodified header values to check against for caching
  14349.      *                           use false to return the header values from this download
  14350.      * @param false|array $accept Accept headers to send
  14351.      * @return string|array  Returns the full path of the downloaded file or a PEAR
  14352.      *                       error on failure.  If the error is caused by
  14353.      *                       socket-related errors, the error object will
  14354.      *                       have the fsockopen error code available through
  14355.      *                       getCode().  If caching is requested, then return the header
  14356.      *                       values.
  14357.      *
  14358.      * @access public
  14359.      */
  14360.     function downloadHttp($url, &$ui, $save_dir = '.', $callback = null, $lastmodified = null,
  14361.                           $accept = false)
  14362.     {
  14363.         static $redirect = 0;
  14364.         // allways reset , so we are clean case of error
  14365.         $wasredirect = $redirect;
  14366.         $redirect = 0;
  14367.         if ($callback) {
  14368.             call_user_func($callback, 'setup', array(&$ui));
  14369.         }
  14370.         $info = parse_url($url);
  14371.         if (!isset($info['scheme']) || !in_array($info['scheme'], array('http', 'https'))) {
  14372.             return PEAR::raiseError('Cannot download non-http URL "' . $url . '"');
  14373.         }
  14374.         if (!isset($info['host'])) {
  14375.             return PEAR::raiseError('Cannot download from non-URL "' . $url . '"');
  14376.         } else {
  14377.             $host = isset($info['host']) ? $info['host'] : null;
  14378.             $port = isset($info['port']) ? $info['port'] : null;
  14379.             $path = isset($info['path']) ? $info['path'] : null;
  14380.         }
  14381.         if (isset($this)) {
  14382.             $config = &$this->config;
  14383.         } else {
  14384.             $config = &PEAR_Config::singleton();
  14385.         }
  14386.         $proxy_host = $proxy_port = $proxy_user = $proxy_pass = '';
  14387.         if ($config->get('http_proxy') && 
  14388.               $proxy = parse_url($config->get('http_proxy'))) {
  14389.             $proxy_host = isset($proxy['host']) ? $proxy['host'] : null;
  14390.             if (isset($proxy['scheme']) && $proxy['scheme'] == 'https') {
  14391.                 $proxy_host = 'ssl://' . $proxy_host;
  14392.             }
  14393.             $proxy_port = isset($proxy['port']) ? $proxy['port'] : 8080;
  14394.             $proxy_user = isset($proxy['user']) ? urldecode($proxy['user']) : null;
  14395.             $proxy_pass = isset($proxy['pass']) ? urldecode($proxy['pass']) : null;
  14396.  
  14397.             if ($callback) {
  14398.                 call_user_func($callback, 'message', "Using HTTP proxy $host:$port");
  14399.             }
  14400.         }
  14401.         if (empty($port)) {
  14402.             if (isset($info['scheme']) && $info['scheme'] == 'https') {
  14403.                 $port = 443;
  14404.             } else {
  14405.                 $port = 80;
  14406.             }
  14407.         }
  14408.         if ($proxy_host != '') {
  14409.             $fp = @fsockopen($proxy_host, $proxy_port, $errno, $errstr);
  14410.             if (!$fp) {
  14411.                 if ($callback) {
  14412.                     call_user_func($callback, 'connfailed', array($proxy_host, $proxy_port,
  14413.                                                                   $errno, $errstr));
  14414.                 }
  14415.                 return PEAR::raiseError("Connection to `$proxy_host:$proxy_port' failed: $errstr", $errno);
  14416.             }
  14417.             if ($lastmodified === false || $lastmodified) {
  14418.                 $request = "GET $url HTTP/1.1\r\n";
  14419.             } else {
  14420.                 $request = "GET $url HTTP/1.0\r\n";
  14421.             }
  14422.         } else {
  14423.             if (isset($info['scheme']) && $info['scheme'] == 'https') {
  14424.                 $host = 'ssl://' . $host;
  14425.             }
  14426.             $fp = @fsockopen($host, $port, $errno, $errstr);
  14427.             if (!$fp) {
  14428.                 if ($callback) {
  14429.                     call_user_func($callback, 'connfailed', array($host, $port,
  14430.                                                                   $errno, $errstr));
  14431.                 }
  14432.                 return PEAR::raiseError("Connection to `$host:$port' failed: $errstr", $errno);
  14433.             }
  14434.             if ($lastmodified === false || $lastmodified) {
  14435.                 $request = "GET $path HTTP/1.1\r\n";
  14436.                 $request .= "Host: $host:$port\r\n";
  14437.             } else {
  14438.                 $request = "GET $path HTTP/1.0\r\n";
  14439.                 $request .= "Host: $host\r\n";
  14440.             }
  14441.         }
  14442.         $ifmodifiedsince = '';
  14443.         if (is_array($lastmodified)) {
  14444.             if (isset($lastmodified['Last-Modified'])) {
  14445.                 $ifmodifiedsince = 'If-Modified-Since: ' . $lastmodified['Last-Modified'] . "\r\n";
  14446.             }
  14447.             if (isset($lastmodified['ETag'])) {
  14448.                 $ifmodifiedsince .= "If-None-Match: $lastmodified[ETag]\r\n";
  14449.             }
  14450.         } else {
  14451.             $ifmodifiedsince = ($lastmodified ? "If-Modified-Since: $lastmodified\r\n" : '');
  14452.         }
  14453.         $request .= $ifmodifiedsince . "User-Agent: PEAR/@package_version@/PHP/" .
  14454.             PHP_VERSION . "\r\n";
  14455.         if (isset($this)) { // only pass in authentication for non-static calls
  14456.             $username = $config->get('username');
  14457.             $password = $config->get('password');
  14458.             if ($username && $password) {
  14459.                 $tmp = base64_encode("$username:$password");
  14460.                 $request .= "Authorization: Basic $tmp\r\n";
  14461.             }
  14462.         }
  14463.         if ($proxy_host != '' && $proxy_user != '') {
  14464.             $request .= 'Proxy-Authorization: Basic ' .
  14465.                 base64_encode($proxy_user . ':' . $proxy_pass) . "\r\n";
  14466.         }
  14467.         if ($accept) {
  14468.             $request .= 'Accept: ' . implode(', ', $accept) . "\r\n";
  14469.         }
  14470.         $request .= "Connection: close\r\n";
  14471.         $request .= "\r\n";
  14472.         fwrite($fp, $request);
  14473.         $headers = array();
  14474.         $reply = 0;
  14475.         while (trim($line = fgets($fp, 1024))) {
  14476.             if (preg_match('/^([^:]+):\s+(.*)\s*$/', $line, $matches)) {
  14477.                 $headers[strtolower($matches[1])] = trim($matches[2]);
  14478.             } elseif (preg_match('|^HTTP/1.[01] ([0-9]{3}) |', $line, $matches)) {
  14479.                 $reply = (int) $matches[1];
  14480.                 if ($reply == 304 && ($lastmodified || ($lastmodified === false))) {
  14481.                     return false;
  14482.                 }
  14483.                 if (! in_array($reply, array(200, 301, 302, 303, 305, 307))) {
  14484.                     return PEAR::raiseError("File http://$host:$port$path not valid (received: $line)");
  14485.                 }
  14486.             }
  14487.         }
  14488.         if ($reply != 200) {
  14489.             if (isset($headers['location'])) {
  14490.                 if ($wasredirect < 5) {
  14491.                     $redirect = $wasredirect + 1;
  14492.                     return $this->downloadHttp($headers['location'],
  14493.                             $ui, $save_dir, $callback, $lastmodified, $accept);
  14494.                 } else {
  14495.                     return PEAR::raiseError("File http://$host:$port$path not valid (redirection looped more than 5 times)");
  14496.                 }
  14497.             } else {
  14498.                 return PEAR::raiseError("File http://$host:$port$path not valid (redirected but no location)");
  14499.             }
  14500.         }
  14501.         if (isset($headers['content-disposition']) &&
  14502.             preg_match('/\sfilename=\"([^;]*\S)\"\s*(;|$)/', $headers['content-disposition'], $matches)) {
  14503.             $save_as = basename($matches[1]);
  14504.         } else {
  14505.             $save_as = basename($url);
  14506.         }
  14507.         if ($callback) {
  14508.             $tmp = call_user_func($callback, 'saveas', $save_as);
  14509.             if ($tmp) {
  14510.                 $save_as = $tmp;
  14511.             }
  14512.         }
  14513.         $dest_file = $save_dir . DIRECTORY_SEPARATOR . $save_as;
  14514.         if (!$wp = @fopen($dest_file, 'wb')) {
  14515.             fclose($fp);
  14516.             if ($callback) {
  14517.                 call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
  14518.             }
  14519.             return PEAR::raiseError("could not open $dest_file for writing");
  14520.         }
  14521.         if (isset($headers['content-length'])) {
  14522.             $length = $headers['content-length'];
  14523.         } else {
  14524.             $length = -1;
  14525.         }
  14526.         $bytes = 0;
  14527.         if ($callback) {
  14528.             call_user_func($callback, 'start', array(basename($dest_file), $length));
  14529.         }
  14530.         while ($data = fread($fp, 1024)) {
  14531.             $bytes += strlen($data);
  14532.             if ($callback) {
  14533.                 call_user_func($callback, 'bytesread', $bytes);
  14534.             }
  14535.             if (!@fwrite($wp, $data)) {
  14536.                 fclose($fp);
  14537.                 if ($callback) {
  14538.                     call_user_func($callback, 'writefailed', array($dest_file, $php_errormsg));
  14539.                 }
  14540.                 return PEAR::raiseError("$dest_file: write failed ($php_errormsg)");
  14541.             }
  14542.         }
  14543.         fclose($fp);
  14544.         fclose($wp);
  14545.         if ($callback) {
  14546.             call_user_func($callback, 'done', $bytes);
  14547.         }
  14548.         if ($lastmodified === false || $lastmodified) {
  14549.             if (isset($headers['etag'])) {
  14550.                 $lastmodified = array('ETag' => $headers['etag']);
  14551.             }
  14552.             if (isset($headers['last-modified'])) {
  14553.                 if (is_array($lastmodified)) {
  14554.                     $lastmodified['Last-Modified'] = $headers['last-modified'];
  14555.                 } else {
  14556.                     $lastmodified = $headers['last-modified'];
  14557.                 }
  14558.             }
  14559.             return array($dest_file, $lastmodified, $headers);
  14560.         }
  14561.         return $dest_file;
  14562.     }
  14563. }
  14564. // }}}
  14565.  
  14566. ?>
  14567. <?php
  14568. /**
  14569.  * PEAR_Downloader_Package
  14570.  *
  14571.  * PHP versions 4 and 5
  14572.  *
  14573.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  14574.  * that is available through the world-wide-web at the following URI:
  14575.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  14576.  * the PHP License and are unable to obtain it through the web, please
  14577.  * send a note to license@php.net so we can mail you a copy immediately.
  14578.  *
  14579.  * @category   pear
  14580.  * @package    PEAR
  14581.  * @author     Greg Beaver <cellog@php.net>
  14582.  * @copyright  1997-2006 The PHP Group
  14583.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  14584.  * @version    CVS: $Id: Package.php,v 1.103 2006/10/12 21:23:59 cellog Exp $
  14585.  * @link       http://pear.php.net/package/PEAR
  14586.  * @since      File available since Release 1.4.0a1
  14587.  */
  14588. /**
  14589.  * Error code when parameter initialization fails because no releases
  14590.  * exist within preferred_state, but releases do exist
  14591.  */
  14592. define('PEAR_DOWNLOADER_PACKAGE_STATE', -1003);
  14593. /**
  14594.  * Coordinates download parameters and manages their dependencies
  14595.  * prior to downloading them.
  14596.  *
  14597.  * Input can come from three sources:
  14598.  *
  14599.  * - local files (archives or package.xml)
  14600.  * - remote files (downloadable urls)
  14601.  * - abstract package names
  14602.  *
  14603.  * The first two elements are handled cleanly by PEAR_PackageFile, but the third requires
  14604.  * accessing pearweb's xml-rpc interface to determine necessary dependencies, and the
  14605.  * format returned of dependencies is slightly different from that used in package.xml.
  14606.  *
  14607.  * This class hides the differences between these elements, and makes automatic
  14608.  * dependency resolution a piece of cake.  It also manages conflicts when
  14609.  * two classes depend on incompatible dependencies, or differing versions of the same
  14610.  * package dependency.  In addition, download will not be attempted if the php version is
  14611.  * not supported, PEAR installer version is not supported, or non-PECL extensions are not
  14612.  * installed.
  14613.  * @category   pear
  14614.  * @package    PEAR
  14615.  * @author     Greg Beaver <cellog@php.net>
  14616.  * @copyright  1997-2006 The PHP Group
  14617.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  14618.  * @version    Release: 1.5.0a2
  14619.  * @link       http://pear.php.net/package/PEAR
  14620.  * @since      Class available since Release 1.4.0a1
  14621.  */
  14622. class PEAR_Downloader_Package
  14623. {
  14624.     /**
  14625.      * @var PEAR_Downloader
  14626.      */
  14627.     var $_downloader;
  14628.     /**
  14629.      * @var PEAR_Config
  14630.      */
  14631.     var $_config;
  14632.     /**
  14633.      * @var PEAR_Registry
  14634.      */
  14635.     var $_registry;
  14636.     /**
  14637.      * Used to implement packagingroot properly
  14638.      * @var PEAR_Registry
  14639.      */
  14640.     var $_installRegistry;
  14641.     /**
  14642.      * @var PEAR_PackageFile_v1|PEAR_PackageFile|v2
  14643.      */
  14644.     var $_packagefile;
  14645.     /**
  14646.      * @var array
  14647.      */
  14648.     var $_parsedname;
  14649.     /**
  14650.      * @var array
  14651.      */
  14652.     var $_downloadURL;
  14653.     /**
  14654.      * @var array
  14655.      */
  14656.     var $_downloadDeps = array();
  14657.     /**
  14658.      * @var boolean
  14659.      */
  14660.     var $_valid = false;
  14661.     /**
  14662.      * @var boolean
  14663.      */
  14664.     var $_analyzed = false;
  14665.     /**
  14666.      * if this or a parent package was invoked with Package-state, this is set to the
  14667.      * state variable.
  14668.      *
  14669.      * This allows temporary reassignment of preferred_state for a parent package and all of
  14670.      * its dependencies.
  14671.      * @var string|false
  14672.      */
  14673.     var $_explicitState = false;
  14674.     /**
  14675.      * If this package is invoked with Package#group, this variable will be true
  14676.      */
  14677.     var $_explicitGroup = false;
  14678.     /**
  14679.      * Package type local|url|xmlrpc
  14680.      * @var string
  14681.      */
  14682.     var $_type;
  14683.     /**
  14684.      * Contents of package.xml, if downloaded from a remote channel
  14685.      * @var string|false
  14686.      * @access private
  14687.      */
  14688.     var $_rawpackagefile;
  14689.     /**
  14690.      * @var boolean
  14691.      * @access private
  14692.      */
  14693.     var $_validated = false;
  14694.  
  14695.     /**
  14696.      * @param PEAR_Downloader
  14697.      */
  14698.     function PEAR_Downloader_Package(&$downloader)
  14699.     {
  14700.         $this->_downloader = &$downloader;
  14701.         $this->_config = &$this->_downloader->config;
  14702.         $this->_registry = &$this->_config->getRegistry();
  14703.         $options = $downloader->getOptions();
  14704.         if (isset($options['packagingroot'])) {
  14705.             $this->_config->setInstallRoot($options['packagingroot']);
  14706.             $this->_installRegistry = &$this->_config->getRegistry();
  14707.             $this->_config->setInstallRoot(false);
  14708.         } else {
  14709.             $this->_installRegistry = &$this->_registry;
  14710.         }
  14711.         $this->_valid = $this->_analyzed = false;
  14712.     }
  14713.  
  14714.     /**
  14715.      * Parse the input and determine whether this is a local file, a remote uri, or an
  14716.      * abstract package name.
  14717.      *
  14718.      * This is the heart of the PEAR_Downloader_Package(), and is used in
  14719.      * {@link PEAR_Downloader::download()}
  14720.      * @param string
  14721.      * @return bool|PEAR_Error
  14722.      */
  14723.     function initialize($param)
  14724.     {
  14725.         $origErr = $this->_fromFile($param);
  14726.         if (!$this->_valid) {
  14727.             $options = $this->_downloader->getOptions();
  14728.             if (isset($options['offline'])) {
  14729.                 if (PEAR::isError($origErr)) {
  14730.                     if (!isset($options['soft'])) {
  14731.                         $this->_downloader->log(0, $origErr->getMessage());
  14732.                     }
  14733.                 }
  14734.                 return PEAR::raiseError('Cannot download non-local package "' . $param . '"');
  14735.             }
  14736.             $err = $this->_fromUrl($param);
  14737.             if (PEAR::isError($err) || !$this->_valid) {
  14738.                 if ($this->_type == 'url') {
  14739.                     if (PEAR::isError($err)) {
  14740.                         if (!isset($options['soft'])) {
  14741.                             $this->_downloader->log(0, $err->getMessage());
  14742.                         }
  14743.                     }
  14744.                     return PEAR::raiseError("Invalid or missing remote package file");
  14745.                 }
  14746.                 $err = $this->_fromString($param);
  14747.                 if (PEAR::isError($err) || !$this->_valid) {
  14748.                     if (PEAR::isError($err) &&
  14749.                           $err->getCode() == PEAR_DOWNLOADER_PACKAGE_STATE) {
  14750.                         return false; // instruct the downloader to silently skip
  14751.                     }
  14752.                     if (isset($this->_type) && $this->_type == 'local' &&
  14753.                           PEAR::isError($origErr)) {
  14754.                         if (is_array($origErr->getUserInfo())) {
  14755.                             foreach ($origErr->getUserInfo() as $err) {
  14756.                                 if (is_array($err)) {
  14757.                                     $err = $err['message'];
  14758.                                 }
  14759.                                 if (!isset($options['soft'])) {
  14760.                                     $this->_downloader->log(0, $err);
  14761.                                 }
  14762.                             }
  14763.                         }
  14764.                         if (!isset($options['soft'])) {
  14765.                             $this->_downloader->log(0, $origErr->getMessage());
  14766.                         }
  14767.                         if (is_array($param)) {
  14768.                             $param = $this->_registry->parsedPackageNameToString($param,
  14769.                                 true);
  14770.                         }
  14771.                         return PEAR::raiseError(
  14772.                             "Cannot initialize '$param', invalid or missing package file");
  14773.                     }
  14774.                     if (PEAR::isError($err)) {
  14775.                         if (!isset($options['soft'])) {
  14776.                             $this->_downloader->log(0, $err->getMessage());
  14777.                         }
  14778.                     }
  14779.                     if (is_array($param)) {
  14780.                         $param = $this->_registry->parsedPackageNameToString($param, true);
  14781.                     }
  14782.                     return PEAR::raiseError(
  14783.                         "Cannot initialize '$param', invalid or missing package file");
  14784.                 }
  14785.             }
  14786.         }
  14787.         return true;
  14788.     }
  14789.  
  14790.     /**
  14791.      * Retrieve any non-local packages
  14792.      * @return PEAR_PackageFile_v1|PEAR_PackageFile_v2|PEAR_Error
  14793.      */
  14794.     function &download()
  14795.     {
  14796.         if (isset($this->_packagefile)) {
  14797.             return $this->_packagefile;
  14798.         }
  14799.         if (isset($this->_downloadURL['url'])) {
  14800.             $this->_isvalid = false;
  14801.             $info = $this->getParsedPackage();
  14802.             foreach ($info as $i => $p) {
  14803.                 $info[$i] = strtolower($p);
  14804.             }
  14805.             $err = $this->_fromUrl($this->_downloadURL['url'],
  14806.                 $this->_registry->parsedPackageNameToString($this->_parsedname, true));
  14807.             $newinfo = $this->getParsedPackage();
  14808.             foreach ($newinfo as $i => $p) {
  14809.                 $newinfo[$i] = strtolower($p);
  14810.             }
  14811.             if ($info != $newinfo) {
  14812.                 do {
  14813.                     if ($info['package'] == 'pecl.php.net' && $newinfo['package'] == 'pear.php.net') {
  14814.                         $info['package'] = 'pear.php.net';
  14815.                         if ($info == $newinfo) {
  14816.                             // skip the channel check if a pecl package says it's a PEAR package
  14817.                             break;
  14818.                         }
  14819.                     }
  14820.                     return PEAR::raiseError('CRITICAL ERROR: We are ' .
  14821.                         $this->_registry->parsedPackageNameToString($info) . ', but the file ' .
  14822.                         'downloaded claims to be ' .
  14823.                         $this->_registry->parsedPackageNameToString($this->getParsedPackage()));
  14824.                 } while (false);
  14825.             }
  14826.             if (PEAR::isError($err) || !$this->_valid) {
  14827.                 return $err;
  14828.             }
  14829.         }
  14830.         $this->_type = 'local';
  14831.         return $this->_packagefile;
  14832.     }
  14833.  
  14834.     function &getPackageFile()
  14835.     {
  14836.         return $this->_packagefile;
  14837.     }
  14838.  
  14839.     function &getDownloader()
  14840.     {
  14841.         return $this->_downloader;
  14842.     }
  14843.  
  14844.     function getType() 
  14845.     {
  14846.         return $this->_type;
  14847.     }
  14848.  
  14849.     /**
  14850.      * Like {@link initialize()}, but operates on a dependency
  14851.      */
  14852.     function fromDepURL($dep)
  14853.     {
  14854.         $this->_downloadURL = $dep;
  14855.         if (isset($dep['uri'])) {
  14856.             $options = $this->_downloader->getOptions();
  14857.             if (!extension_loaded("zlib") || isset($options['nocompress'])) {
  14858.                 $ext = '.tar';
  14859.             } else {
  14860.                 $ext = '.tgz';
  14861.             }
  14862.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  14863.             $err = $this->_fromUrl($dep['uri'] . $ext);
  14864.             PEAR::popErrorHandling();
  14865.             if (PEAR::isError($err)) {
  14866.                 if (!isset($options['soft'])) {
  14867.                     $this->_downloader->log(0, $err->getMessage());
  14868.                 }
  14869.                 return PEAR::raiseError('Invalid uri dependency "' . $dep['uri'] . $ext . '", ' .
  14870.                     'cannot download');
  14871.             }
  14872.         } else {
  14873.             $this->_parsedname =
  14874.                 array(
  14875.                     'package' => $dep['info']->getPackage(),
  14876.                     'channel' => $dep['info']->getChannel(),
  14877.                     'version' => $dep['version']
  14878.                 );
  14879.             if (!isset($dep['nodefault'])) {
  14880.                 $this->_parsedname['group'] = 'default'; // download the default dependency group
  14881.                 $this->_explicitGroup = false;
  14882.             }
  14883.             $this->_rawpackagefile = $dep['raw'];
  14884.         }
  14885.     }
  14886.  
  14887.     function detectDependencies($params)
  14888.     {
  14889.         $options = $this->_downloader->getOptions();
  14890.         if (isset($options['downloadonly'])) {
  14891.             return;
  14892.         }
  14893.         if (isset($options['offline'])) {
  14894.             $this->_downloader->log(3, 'Skipping dependency download check, --offline specified');
  14895.             return;
  14896.         }
  14897.         $pname = $this->getParsedPackage();
  14898.         if (!$pname) {
  14899.             return;
  14900.         }
  14901.         $deps = $this->getDeps();
  14902.         if (!$deps) {
  14903.             return;
  14904.         }
  14905.         if (isset($deps['required'])) { // package.xml 2.0
  14906.             return $this->_detect2($deps, $pname, $options, $params);
  14907.         } else {
  14908.             return $this->_detect1($deps, $pname, $options, $params);
  14909.         }
  14910.     }
  14911.  
  14912.     function setValidated()
  14913.     {
  14914.         $this->_validated = true;
  14915.     }
  14916.  
  14917.     function alreadyValidated()
  14918.     {
  14919.         return $this->_validated;
  14920.     }
  14921.  
  14922.     /**
  14923.      * Remove packages to be downloaded that are already installed
  14924.      * @param array of PEAR_Downloader_Package objects
  14925.      * @static
  14926.      */
  14927.     function removeInstalled(&$params)
  14928.     {
  14929.         if (!isset($params[0])) {
  14930.             return;
  14931.         }
  14932.         $options = $params[0]->_downloader->getOptions();
  14933.         if (!isset($options['downloadonly'])) {
  14934.             foreach ($params as $i => $param) {
  14935.                 // remove self if already installed with this version
  14936.                 // this does not need any pecl magic - we only remove exact matches
  14937.                 if ($param->_installRegistry->packageExists($param->getPackage(), $param->getChannel())) {
  14938.                     if (version_compare($param->_installRegistry->packageInfo($param->getPackage(), 'version',
  14939.                           $param->getChannel()), $param->getVersion(), '==')) {
  14940.                         if (!isset($options['force'])) {
  14941.                             $info = $param->getParsedPackage();
  14942.                             unset($info['version']);
  14943.                             unset($info['state']);
  14944.                             if (!isset($options['soft'])) {
  14945.                                 $param->_downloader->log(1, 'Skipping package "' .
  14946.                                     $param->getShortName() .
  14947.                                     '", already installed as version ' .
  14948.                                     $param->_installRegistry->packageInfo($param->getPackage(),
  14949.                                         'version', $param->getChannel()));
  14950.                             }
  14951.                             $params[$i] = false;
  14952.                         }
  14953.                     } elseif (!isset($options['force']) && !isset($options['upgrade']) &&
  14954.                           !isset($options['soft'])) {
  14955.                         $info = $param->getParsedPackage();
  14956.                         $param->_downloader->log(1, 'Skipping package "' .
  14957.                             $param->getShortName() .
  14958.                             '", already installed as version ' .
  14959.                             $param->_installRegistry->packageInfo($param->getPackage(), 'version',
  14960.                                 $param->getChannel()));
  14961.                         $params[$i] = false;
  14962.                     }
  14963.                 }
  14964.             }
  14965.         }
  14966.         PEAR_Downloader_Package::removeDuplicates($params);
  14967.     }
  14968.  
  14969.     function _detect2($deps, $pname, $options, $params)
  14970.     {
  14971.         $this->_downloadDeps = array();
  14972.         $groupnotfound = false;
  14973.         foreach (array('package', 'subpackage') as $packagetype) {
  14974.             // get required dependency group
  14975.             if (isset($deps['required'][$packagetype])) {
  14976.                 if (isset($deps['required'][$packagetype][0])) {
  14977.                     foreach ($deps['required'][$packagetype] as $dep) {
  14978.                         if (isset($dep['conflicts'])) {
  14979.                             // skip any package that this package conflicts with
  14980.                             continue;
  14981.                         }
  14982.                         $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  14983.                         if (is_array($ret)) {
  14984.                             $this->_downloadDeps[] = $ret;
  14985.                         }
  14986.                     }
  14987.                 } else {
  14988.                     $dep = $deps['required'][$packagetype];
  14989.                     if (!isset($dep['conflicts'])) {
  14990.                         // skip any package that this package conflicts with
  14991.                         $ret = $this->_detect2Dep($dep, $pname, 'required', $params);
  14992.                         if (is_array($ret)) {
  14993.                             $this->_downloadDeps[] = $ret;
  14994.                         }
  14995.                     }
  14996.                 }
  14997.             }
  14998.             // get optional dependency group, if any
  14999.             if (isset($deps['optional'][$packagetype])) {
  15000.                 $skipnames = array();
  15001.                 if (!isset($deps['optional'][$packagetype][0])) {
  15002.                     $deps['optional'][$packagetype] = array($deps['optional'][$packagetype]);
  15003.                 }
  15004.                 foreach ($deps['optional'][$packagetype] as $dep) {
  15005.                     $skip = false;
  15006.                     if (!isset($options['alldeps'])) {
  15007.                         $dep['package'] = $dep['name'];
  15008.                         if (!isset($options['soft'])) {
  15009.                             $this->_downloader->log(3, 'Notice: package "' .
  15010.                               $this->_registry->parsedPackageNameToString($this->getParsedPackage(),
  15011.                                     true) . '" optional dependency "' .
  15012.                                 $this->_registry->parsedPackageNameToString(array('package' =>
  15013.                                     $dep['name'], 'channel' => 'pear.php.net'), true) .
  15014.                                 '" will not be automatically downloaded');
  15015.                         }
  15016.                         $skipnames[] = $this->_registry->parsedPackageNameToString($dep, true);
  15017.                         $skip = true;
  15018.                         unset($dep['package']);
  15019.                     }
  15020.                     if (!($ret = $this->_detect2Dep($dep, $pname, 'optional', $params))) {
  15021.                         $dep['package'] = $dep['name'];
  15022.                         $skip = count($skipnames) ?
  15023.                             $skipnames[count($skipnames) - 1] : '';
  15024.                         if ($skip ==
  15025.                               $this->_registry->parsedPackageNameToString($dep, true)) {
  15026.                             array_pop($skipnames);
  15027.                         }
  15028.                     }
  15029.                     if (!$skip && is_array($ret)) {
  15030.                         $this->_downloadDeps[] = $ret;
  15031.                     }
  15032.                 }
  15033.                 if (count($skipnames)) {
  15034.                     if (!isset($options['soft'])) {
  15035.                         $this->_downloader->log(1, 'Did not download optional dependencies: ' .
  15036.                             implode(', ', $skipnames) .
  15037.                             ', use --alldeps to download automatically');
  15038.                     }
  15039.                 }
  15040.             }
  15041.             // get requested dependency group, if any
  15042.             $groupname = $this->getGroup();
  15043.             $explicit = $this->_explicitGroup;
  15044.             if (!$groupname) {
  15045.                 if ($this->canDefault()) {
  15046.                     $groupname = 'default'; // try the default dependency group
  15047.                 } else {
  15048.                     continue;
  15049.                 }
  15050.             }
  15051.             if ($groupnotfound) {
  15052.                 continue;
  15053.             }
  15054.             if (isset($deps['group'])) {
  15055.                 if (isset($deps['group']['attribs'])) {
  15056.                     if (strtolower($deps['group']['attribs']['name']) == strtolower($groupname)) {
  15057.                         $group = $deps['group'];
  15058.                     } elseif ($explicit) {
  15059.                         if (!isset($options['soft'])) {
  15060.                             $this->_downloader->log(0, 'Warning: package "' .
  15061.                                 $this->_registry->parsedPackageNameToString($pname, true) .
  15062.                                 '" has no dependency ' . 'group named "' . $groupname . '"');
  15063.                         }
  15064.                         $groupnotfound = true;
  15065.                         continue;
  15066.                     }
  15067.                 } else {
  15068.                     $found = false;
  15069.                     foreach ($deps['group'] as $group) {
  15070.                         if (strtolower($group['attribs']['name']) == strtolower($groupname)) {
  15071.                             $found = true;
  15072.                             break;
  15073.                         }
  15074.                     }
  15075.                     if (!$found) {
  15076.                         if ($explicit) {
  15077.                             if (!isset($options['soft'])) {
  15078.                                 $this->_downloader->log(0, 'Warning: package "' .
  15079.                                     $this->_registry->parsedPackageNameToString($pname, true) .
  15080.                                     '" has no dependency ' . 'group named "' . $groupname . '"');
  15081.                             }
  15082.                         }
  15083.                         $groupnotfound = true;
  15084.                         continue;
  15085.                     }
  15086.                 }
  15087.             }
  15088.             if (isset($group)) {
  15089.                 if (isset($group[$packagetype])) {
  15090.                     if (isset($group[$packagetype][0])) {
  15091.                         foreach ($group[$packagetype] as $dep) {
  15092.                             $ret = $this->_detect2Dep($dep, $pname, 'dependency group "' .
  15093.                                 $group['attribs']['name'] . '"', $params);
  15094.                             if (is_array($ret)) {
  15095.                                 $this->_downloadDeps[] = $ret;
  15096.                             }
  15097.                         }
  15098.                     } else {
  15099.                         $ret = $this->_detect2Dep($group[$packagetype], $pname,
  15100.                             'dependency group "' .
  15101.                             $group['attribs']['name'] . '"', $params);
  15102.                         if (is_array($ret)) {
  15103.                             $this->_downloadDeps[] = $ret;
  15104.                         }
  15105.                     }
  15106.                 }
  15107.             }
  15108.         }
  15109.     }
  15110.  
  15111.     function _detect2Dep($dep, $pname, $group, $params)
  15112.     {
  15113.         if (isset($dep['conflicts'])) {
  15114.             return true;
  15115.         }
  15116.         $options = $this->_downloader->getOptions();
  15117.         if (isset($dep['uri'])) {
  15118.             return array('uri' => $dep['uri'], 'dep' => $dep);;
  15119.         }
  15120.         $testdep = $dep;
  15121.         $testdep['package'] = $dep['name'];
  15122.         if (PEAR_Downloader_Package::willDownload($testdep, $params)) {
  15123.             $dep['package'] = $dep['name'];
  15124.             if (!isset($options['soft'])) {
  15125.                 $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group .
  15126.                     ' dependency "' .
  15127.                     $this->_registry->parsedPackageNameToString($dep, true) .
  15128.                     '", will be installed');
  15129.             }
  15130.             return false;
  15131.         }
  15132.         $options = $this->_downloader->getOptions();
  15133.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15134.         if ($this->_explicitState) {
  15135.             $pname['state'] = $this->_explicitState;
  15136.         }
  15137.         $url =
  15138.             $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  15139.         if (PEAR::isError($url)) {
  15140.             PEAR::popErrorHandling();
  15141.             return $url;
  15142.         }
  15143.         $dep['package'] = $dep['name'];
  15144.         $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params, $group == 'optional' &&
  15145.             !isset($options['alldeps']), true);
  15146.         PEAR::popErrorHandling();
  15147.         if (PEAR::isError($ret)) {
  15148.             if (!isset($options['soft'])) {
  15149.                 $this->_downloader->log(0, $ret->getMessage());
  15150.             }
  15151.             return false;
  15152.         } else {
  15153.             // check to see if a dep is already installed and is the same or newer
  15154.             if (!isset($dep['min']) && !isset($dep['max']) && !isset($dep['recommended'])) {
  15155.                 $oper = 'has';
  15156.             } else {
  15157.                 $oper = 'gt';
  15158.             }
  15159.             // do not try to move this before getDepPackageDownloadURL
  15160.             // we can't determine whether upgrade is necessary until we know what
  15161.             // version would be downloaded
  15162.             if (!isset($options['force']) && $this->isInstalled($ret, $oper)) {
  15163.                 $version = $this->_installRegistry->packageInfo($dep['name'], 'version',
  15164.                     $dep['channel']);
  15165.                 $dep['package'] = $dep['name'];
  15166.                 if (!isset($options['soft'])) {
  15167.                     $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  15168.                         ' dependency "' .
  15169.                     $this->_registry->parsedPackageNameToString($dep, true) .
  15170.                         '" version ' . $url['version'] . ', already installed as version ' .
  15171.                         $version);
  15172.                 }
  15173.                 return false;
  15174.             }
  15175.         }
  15176.         if (isset($dep['nodefault'])) {
  15177.             $ret['nodefault'] = true;
  15178.         }
  15179.         return $ret;
  15180.     }
  15181.  
  15182.     function _detect1($deps, $pname, $options, $params)
  15183.     {
  15184.         $this->_downloadDeps = array();
  15185.         $skipnames = array();
  15186.         foreach ($deps as $dep) {
  15187.             $nodownload = false;
  15188.             if ($dep['type'] == 'pkg') {
  15189.                 $dep['channel'] = 'pear.php.net';
  15190.                 $dep['package'] = $dep['name'];
  15191.                 switch ($dep['rel']) {
  15192.                     case 'not' :
  15193.                         continue 2;
  15194.                     case 'ge' :
  15195.                     case 'eq' :
  15196.                     case 'gt' :
  15197.                     case 'has' :
  15198.                         $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  15199.                             'required' :
  15200.                             'optional';
  15201.                         if (PEAR_Downloader_Package::willDownload($dep, $params)) {
  15202.                             $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  15203.                                 . ' dependency "' .
  15204.                                 $this->_registry->parsedPackageNameToString($dep, true) .
  15205.                                 '", will be installed');
  15206.                             continue 2;
  15207.                         }
  15208.                         $fakedp = new PEAR_PackageFile_v1;
  15209.                         $fakedp->setPackage($dep['name']);
  15210.                         // skip internet check if we are not upgrading (bug #5810)
  15211.                         if (!isset($options['upgrade']) && $this->isInstalled(
  15212.                               $fakedp, $dep['rel'])) {
  15213.                             $this->_downloader->log(2, $this->getShortName() . ': Skipping ' . $group
  15214.                                 . ' dependency "' .
  15215.                                 $this->_registry->parsedPackageNameToString($dep, true) .
  15216.                                 '", is already installed');
  15217.                             continue 2;
  15218.                         }
  15219.                 }
  15220.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15221.                 if ($this->_explicitState) {
  15222.                     $pname['state'] = $this->_explicitState;
  15223.                 }
  15224.                 $url =
  15225.                     $this->_downloader->_getDepPackageDownloadUrl($dep, $pname);
  15226.                 $chan = 'pear.php.net';
  15227.                 if (PEAR::isError($url)) {
  15228.                     // check to see if this is a pecl package that has jumped
  15229.                     // from pear.php.net to pecl.php.net channel
  15230.                     if (!class_exists('PEAR_Dependency2')) {
  15231.                         require_once 'phar://go-pear.phar/PEAR/Dependency2.php';
  15232.                     }
  15233.                     $newdep = PEAR_Dependency2::normalizeDep($dep);
  15234.                     $newdep = $newdep[0];
  15235.                     $newdep['channel'] = 'pecl.php.net';
  15236.                     $chan = 'pecl.php.net';
  15237.                     $url =
  15238.                         $this->_downloader->_getDepPackageDownloadUrl($newdep, $pname);
  15239.                     $obj = &$this->_installRegistry->getPackage($dep['name']);
  15240.                     if (PEAR::isError($url)) {
  15241.                         PEAR::popErrorHandling();
  15242.                         if ($obj !== null && $this->isInstalled($obj, $dep['rel'])) {
  15243.                             $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  15244.                                 'required' :
  15245.                                 'optional';
  15246.                             $dep['package'] = $dep['name'];
  15247.                             if (!isset($options['soft'])) {
  15248.                                 $this->_downloader->log(3, $this->getShortName() .
  15249.                                     ': Skipping ' . $group . ' dependency "' .
  15250.                                     $this->_registry->parsedPackageNameToString($dep, true) .
  15251.                                     '", already installed as version ' . $obj->getVersion());
  15252.                             }
  15253.                             $skip = count($skipnames) ?
  15254.                                 $skipnames[count($skipnames) - 1] : '';
  15255.                             if ($skip ==
  15256.                                   $this->_registry->parsedPackageNameToString($dep, true)) {
  15257.                                 array_pop($skipnames);
  15258.                             }
  15259.                             continue;
  15260.                         } else {
  15261.                             if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  15262.                                 $this->_downloader->log(2, $this->getShortName() .
  15263.                                     ': Skipping ' . $group
  15264.                                     . ' dependency "' .
  15265.                                     $this->_registry->parsedPackageNameToString($dep, true) .
  15266.                                     '", no releases exist');
  15267.                                 continue;
  15268.                             } else {
  15269.                                 return $url;
  15270.                             }
  15271.                         }
  15272.                     }
  15273.                 }
  15274.                 PEAR::popErrorHandling();
  15275.                 if (!isset($options['alldeps'])) {
  15276.                     if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  15277.                         if (!isset($options['soft'])) {
  15278.                             $this->_downloader->log(3, 'Notice: package "' .
  15279.                                 $this->getShortName() .
  15280.                                 '" optional dependency "' .
  15281.                                 $this->_registry->parsedPackageNameToString(
  15282.                                     array('channel' => $chan, 'package' =>
  15283.                                     $dep['name']), true) .
  15284.                                 '" will not be automatically downloaded');
  15285.                         }
  15286.                         $skipnames[] = $this->_registry->parsedPackageNameToString(
  15287.                                 array('channel' => $chan, 'package' =>
  15288.                                 $dep['name']), true);
  15289.                         $nodownload = true;
  15290.                     }
  15291.                 }
  15292.                 if (!isset($options['alldeps']) && !isset($options['onlyreqdeps'])) {
  15293.                     if (!isset($dep['optional']) || $dep['optional'] == 'no') {
  15294.                         if (!isset($options['soft'])) {
  15295.                             $this->_downloader->log(3, 'Notice: package "' .
  15296.                                 $this->getShortName() .
  15297.                                 '" required dependency "' .
  15298.                                 $this->_registry->parsedPackageNameToString(
  15299.                                     array('channel' => $chan, 'package' =>
  15300.                                     $dep['name']), true) .
  15301.                                 '" will not be automatically downloaded');
  15302.                         }
  15303.                         $skipnames[] = $this->_registry->parsedPackageNameToString(
  15304.                                 array('channel' => $chan, 'package' =>
  15305.                                 $dep['name']), true);
  15306.                         $nodownload = true;
  15307.                     }
  15308.                 }
  15309.                 // check to see if a dep is already installed
  15310.                 // do not try to move this before getDepPackageDownloadURL
  15311.                 // we can't determine whether upgrade is necessary until we know what
  15312.                 // version would be downloaded
  15313.                 if (!isset($options['force']) && $this->isInstalled(
  15314.                         $url, $dep['rel'])) {
  15315.                     $group = (!isset($dep['optional']) || $dep['optional'] == 'no') ?
  15316.                         'required' :
  15317.                         'optional';
  15318.                     $dep['package'] = $dep['name'];
  15319.                     if (isset($newdep)) {
  15320.                         $version = $this->_installRegistry->packageInfo($newdep['name'], 'version',
  15321.                             $newdep['channel']);
  15322.                     } else {
  15323.                         $version = $this->_installRegistry->packageInfo($dep['name'], 'version');
  15324.                     }
  15325.                     $dep['version'] = $url['version'];
  15326.                     if (!isset($options['soft'])) {
  15327.                         $this->_downloader->log(3, $this->getShortName() . ': Skipping ' . $group .
  15328.                             ' dependency "' .
  15329.                             $this->_registry->parsedPackageNameToString($dep, true) .
  15330.                             '", already installed as version ' . $version);
  15331.                     }
  15332.                     $skip = count($skipnames) ?
  15333.                         $skipnames[count($skipnames) - 1] : '';
  15334.                     if ($skip ==
  15335.                           $this->_registry->parsedPackageNameToString($dep, true)) {
  15336.                         array_pop($skipnames);
  15337.                     }
  15338.                     continue;
  15339.                 }
  15340.                 if ($nodownload) {
  15341.                     continue;
  15342.                 }
  15343.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15344.                 if (isset($newdep)) {
  15345.                     $dep = $newdep;
  15346.                 }
  15347.                 $dep['package'] = $dep['name'];
  15348.                 $ret = $this->_analyzeDownloadURL($url, 'dependency', $dep, $params,
  15349.                     isset($dep['optional']) && $dep['optional'] == 'yes' &&
  15350.                     !isset($options['alldeps']), true);
  15351.                 PEAR::popErrorHandling();
  15352.                 if (PEAR::isError($ret)) {
  15353.                     if (!isset($options['soft'])) {
  15354.                         $this->_downloader->log(0, $ret->getMessage());
  15355.                     }
  15356.                     continue;
  15357.                 }
  15358.                 $this->_downloadDeps[] = $ret;
  15359.             }
  15360.         }
  15361.         if (count($skipnames)) {
  15362.             if (!isset($options['soft'])) {
  15363.                 $this->_downloader->log(1, 'Did not download dependencies: ' .
  15364.                     implode(', ', $skipnames) .
  15365.                     ', use --alldeps or --onlyreqdeps to download automatically');
  15366.             }
  15367.         }
  15368.     }
  15369.  
  15370.     function setDownloadURL($pkg)
  15371.     {
  15372.         $this->_downloadURL = $pkg;
  15373.     }
  15374.  
  15375.     /**
  15376.      * Set the package.xml object for this downloaded package
  15377.      *
  15378.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 $pkg
  15379.      */
  15380.     function setPackageFile(&$pkg)
  15381.     {
  15382.         $this->_packagefile = &$pkg;
  15383.     }
  15384.  
  15385.     function getShortName()
  15386.     {
  15387.         return $this->_registry->parsedPackageNameToString(array('channel' => $this->getChannel(),
  15388.             'package' => $this->getPackage()), true);
  15389.     }
  15390.  
  15391.     function getParsedPackage()
  15392.     {   
  15393.         if (isset($this->_packagefile) || isset($this->_parsedname)) {
  15394.             return array('channel' => $this->getChannel(),
  15395.                 'package' => $this->getPackage(),
  15396.                 'version' => $this->getVersion());
  15397.         }
  15398.         return false;
  15399.     }
  15400.  
  15401.     function getDownloadURL()
  15402.     {
  15403.         return $this->_downloadURL;
  15404.     }
  15405.  
  15406.     function canDefault()
  15407.     {
  15408.         if (isset($this->_downloadURL)) {
  15409.             if (isset($this->_downloadURL['nodefault'])) {
  15410.                 return false;
  15411.             }
  15412.         }
  15413.         return true;
  15414.     }
  15415.  
  15416.     function getPackage()
  15417.     {
  15418.         if (isset($this->_packagefile)) {
  15419.             return $this->_packagefile->getPackage();
  15420.         } elseif (isset($this->_downloadURL['info'])) {
  15421.             return $this->_downloadURL['info']->getPackage();
  15422.         } else {
  15423.             return false;
  15424.         }
  15425.     }
  15426.  
  15427.     /**
  15428.      * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2
  15429.      */
  15430.     function isSubpackage(&$pf)
  15431.     {
  15432.         if (isset($this->_packagefile)) {
  15433.             return $this->_packagefile->isSubpackage($pf);
  15434.         } elseif (isset($this->_downloadURL['info'])) {
  15435.             return $this->_downloadURL['info']->isSubpackage($pf);
  15436.         } else {
  15437.             return false;
  15438.         }
  15439.     }
  15440.  
  15441.     function getPackageType()
  15442.     {
  15443.         if (isset($this->_packagefile)) {
  15444.             return $this->_packagefile->getPackageType();
  15445.         } elseif (isset($this->_downloadURL['info'])) {
  15446.             return $this->_downloadURL['info']->getPackageType();
  15447.         } else {
  15448.             return false;
  15449.         }
  15450.     }
  15451.  
  15452.     function isBundle()
  15453.     {
  15454.         if (isset($this->_packagefile)) {
  15455.             return $this->_packagefile->getPackageType() == 'bundle';
  15456.         } else {
  15457.             return false;
  15458.         }
  15459.     }
  15460.  
  15461.     function getPackageXmlVersion()
  15462.     {
  15463.         if (isset($this->_packagefile)) {
  15464.             return $this->_packagefile->getPackagexmlVersion();
  15465.         } elseif (isset($this->_downloadURL['info'])) {
  15466.             return $this->_downloadURL['info']->getPackagexmlVersion();
  15467.         } else {
  15468.             return '1.0';
  15469.         }
  15470.     }
  15471.  
  15472.     function getChannel()
  15473.     {
  15474.         if (isset($this->_packagefile)) {
  15475.             return $this->_packagefile->getChannel();
  15476.         } elseif (isset($this->_downloadURL['info'])) {
  15477.             return $this->_downloadURL['info']->getChannel();
  15478.         } else {
  15479.             return false;
  15480.         }
  15481.     }
  15482.  
  15483.     function getURI()
  15484.     {
  15485.         if (isset($this->_packagefile)) {
  15486.             return $this->_packagefile->getURI();
  15487.         } elseif (isset($this->_downloadURL['info'])) {
  15488.             return $this->_downloadURL['info']->getURI();
  15489.         } else {
  15490.             return false;
  15491.         }
  15492.     }
  15493.  
  15494.     function getVersion()
  15495.     {
  15496.         if (isset($this->_packagefile)) {
  15497.             return $this->_packagefile->getVersion();
  15498.         } elseif (isset($this->_downloadURL['version'])) {
  15499.             return $this->_downloadURL['version'];
  15500.         } else {
  15501.             return false;
  15502.         }
  15503.     }
  15504.  
  15505.     function isCompatible($pf)
  15506.     {
  15507.         if (isset($this->_packagefile)) {
  15508.             return $this->_packagefile->isCompatible($pf);
  15509.         } elseif (isset($this->_downloadURL['info'])) {
  15510.             return $this->_downloadURL['info']->isCompatible($pf);
  15511.         } else {
  15512.             return true;
  15513.         }
  15514.     }
  15515.  
  15516.     function setGroup($group)
  15517.     {
  15518.         $this->_parsedname['group'] = $group;
  15519.     }
  15520.  
  15521.     function getGroup()
  15522.     {
  15523.         if (isset($this->_parsedname['group'])) {
  15524.             return $this->_parsedname['group'];
  15525.         } else {
  15526.             return '';
  15527.         }
  15528.     }
  15529.  
  15530.     function isExtension($name)
  15531.     {
  15532.         if (isset($this->_packagefile)) {
  15533.             return $this->_packagefile->isExtension($name);
  15534.         } elseif (isset($this->_downloadURL['info'])) {
  15535.             if ($this->_downloadURL['info']->getPackagexmlVersion() == '2.0') {
  15536.                 return $this->_downloadURL['info']->getProvidesExtension() == $name;
  15537.             } else {
  15538.                 return false;
  15539.             }
  15540.         } else {
  15541.             return false;
  15542.         }
  15543.     }
  15544.  
  15545.     function getDeps()
  15546.     {
  15547.         if (isset($this->_packagefile)) {
  15548.             $ver = $this->_packagefile->getPackagexmlVersion();
  15549.             if (version_compare($ver, '2.0', '>=')) {
  15550.                 return $this->_packagefile->getDeps(true);
  15551.             } else {
  15552.                 return $this->_packagefile->getDeps();
  15553.             }
  15554.         } elseif (isset($this->_downloadURL['info'])) {
  15555.             $ver = $this->_downloadURL['info']->getPackagexmlVersion();
  15556.             if (version_compare($ver, '2.0', '>=')) {
  15557.                 return $this->_downloadURL['info']->getDeps(true);
  15558.             } else {
  15559.                 return $this->_downloadURL['info']->getDeps();
  15560.             }
  15561.         } else {
  15562.             return array();
  15563.         }
  15564.     }
  15565.  
  15566.     /**
  15567.      * @param array Parsed array from {@link PEAR_Registry::parsePackageName()} or a dependency
  15568.      *                     returned from getDepDownloadURL()
  15569.      */
  15570.     function isEqual($param)
  15571.     {
  15572.         if (is_object($param)) {
  15573.             $channel = $param->getChannel();
  15574.             $package = $param->getPackage();
  15575.             if ($param->getURI()) {
  15576.                 $param = array(
  15577.                     'channel' => $param->getChannel(),
  15578.                     'package' => $param->getPackage(),
  15579.                     'version' => $param->getVersion(),
  15580.                     'uri' => $param->getURI(),
  15581.                 );
  15582.             } else {
  15583.                 $param = array(
  15584.                     'channel' => $param->getChannel(),
  15585.                     'package' => $param->getPackage(),
  15586.                     'version' => $param->getVersion(),
  15587.                 );
  15588.             }
  15589.         } else {
  15590.             if (isset($param['uri'])) {
  15591.                 if ($this->getChannel() != '__uri') {
  15592.                     return false;
  15593.                 }
  15594.                 return $param['uri'] == $this->getURI();
  15595.             }
  15596.             $package = isset($param['package']) ? $param['package'] :
  15597.                 $param['info']->getPackage();
  15598.             $channel = isset($param['channel']) ? $param['channel'] :
  15599.                 $param['info']->getChannel();
  15600.             if (isset($param['rel'])) {
  15601.                 if (!class_exists('PEAR_Dependency2')) {
  15602.                     require_once 'phar://go-pear.phar/PEAR/Dependency2.php';
  15603.                 }
  15604.                 $newdep = PEAR_Dependency2::normalizeDep($param);
  15605.                 $newdep = $newdep[0];
  15606.             } elseif (isset($param['min'])) {
  15607.                 $newdep = $param;
  15608.             }
  15609.         }
  15610.         if (isset($newdep)) {
  15611.             if (!isset($newdep['min'])) {
  15612.                 $newdep['min'] = '0';
  15613.             }
  15614.             if (!isset($newdep['max'])) {
  15615.                 $newdep['max'] = '100000000000000000000';
  15616.             }
  15617.             // use magic to support pecl packages suddenly jumping to the pecl channel
  15618.             // we need to support both dependency possibilities
  15619.             if ($channel == 'pear.php.net' && $this->getChannel() == 'pecl.php.net') {
  15620.                 if ($package == $this->getPackage()) {
  15621.                     $channel = 'pecl.php.net';
  15622.                 }
  15623.             }
  15624.             if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  15625.                 if ($package == $this->getPackage()) {
  15626.                     $channel = 'pear.php.net';
  15627.                 }
  15628.             }
  15629.             return (strtolower($package) == strtolower($this->getPackage()) &&
  15630.                 $channel == $this->getChannel() &&
  15631.                 version_compare($newdep['min'], $this->getVersion(), '<=') &&
  15632.                 version_compare($newdep['max'], $this->getVersion(), '>='));
  15633.         }
  15634.         // use magic to support pecl packages suddenly jumping to the pecl channel
  15635.         if ($channel == 'pecl.php.net' && $this->getChannel() == 'pear.php.net') {
  15636.             if (strtolower($package) == strtolower($this->getPackage())) {
  15637.                 $channel = 'pear.php.net';
  15638.             }
  15639.         }
  15640.         if (isset($param['version'])) {
  15641.             return (strtolower($package) == strtolower($this->getPackage()) &&
  15642.                 $channel == $this->getChannel() &&
  15643.                 $param['version'] == $this->getVersion());
  15644.         } else {
  15645.             return strtolower($package) == strtolower($this->getPackage()) &&
  15646.                 $channel == $this->getChannel();
  15647.         }
  15648.     }
  15649.  
  15650.     function isInstalled($dep, $oper = '==')
  15651.     {
  15652.         if (!$dep) {
  15653.             return false;
  15654.         }
  15655.         if ($oper != 'ge' && $oper != 'gt' && $oper != 'has' && $oper != '==') {
  15656.             return false;
  15657.         }
  15658.         if (is_object($dep)) {
  15659.             $package = $dep->getPackage();
  15660.             $channel = $dep->getChannel();
  15661.             if ($dep->getURI()) {
  15662.                 $dep = array(
  15663.                     'uri' => $dep->getURI(),
  15664.                     'version' => $dep->getVersion(),
  15665.                 );
  15666.             } else {
  15667.                 $dep = array(
  15668.                     'version' => $dep->getVersion(),
  15669.                 );
  15670.             }
  15671.         } else {
  15672.             if (isset($dep['uri'])) {
  15673.                 $channel = '__uri';
  15674.                 $package = $dep['dep']['name'];
  15675.             } else {
  15676.                 $channel = $dep['info']->getChannel();
  15677.                 $package = $dep['info']->getPackage();
  15678.             }
  15679.         }
  15680.         $options = $this->_downloader->getOptions();
  15681.         $test = $this->_installRegistry->packageExists($package, $channel);
  15682.         if (!$test && $channel == 'pecl.php.net') {
  15683.             // do magic to allow upgrading from old pecl packages to new ones
  15684.             $test = $this->_installRegistry->packageExists($package, 'pear.php.net');
  15685.             $channel = 'pear.php.net';
  15686.         }
  15687.         if ($test) {
  15688.             if (isset($dep['uri'])) {
  15689.                 if ($this->_installRegistry->packageInfo($package, 'uri', '__uri') == $dep['uri']) {
  15690.                     return true;
  15691.                 }
  15692.             }
  15693.             if (isset($options['upgrade'])) {
  15694.                 if ($oper == 'has') {
  15695.                     if (version_compare($this->_installRegistry->packageInfo(
  15696.                           $package, 'version', $channel),
  15697.                           $dep['version'], '>=')) {
  15698.                         return true;
  15699.                     } else {
  15700.                         return false;
  15701.                     }
  15702.                 } else {
  15703.                     if (version_compare($this->_installRegistry->packageInfo(
  15704.                           $package, 'version', $channel),
  15705.                           $dep['version'], '>=')) {
  15706.                         return true;
  15707.                     }
  15708.                     return false;
  15709.                 }
  15710.             }
  15711.             return true;
  15712.         }
  15713.         return false;
  15714.     }
  15715.  
  15716.     /**
  15717.      * @param array
  15718.      * @static
  15719.      */
  15720.     function removeDuplicates(&$params)
  15721.     {
  15722.         $pnames = array();
  15723.         foreach ($params as $i => $param) {
  15724.             if (!$param) {
  15725.                 continue;
  15726.             }
  15727.             if ($param->getPackage()) {
  15728.                 $pnames[$i] = $param->getChannel() . '/' .
  15729.                     $param->getPackage() . '-' . $param->getVersion() . '#' . $param->getGroup();
  15730.             }
  15731.         }
  15732.         $pnames = array_unique($pnames);
  15733.         $unset = array_diff(array_keys($params), array_keys($pnames));
  15734.         $testp = array_flip($pnames);
  15735.         foreach ($params as $i => $param) {
  15736.             if (!$param) {
  15737.                 $unset[] = $i;
  15738.                 continue;
  15739.             }
  15740.             if (!is_a($param, 'PEAR_Downloader_Package')) {
  15741.                 $unset[] = $i;
  15742.                 continue;
  15743.             }
  15744.             if (!isset($testp[$param->getChannel() . '/' . $param->getPackage() . '-' .
  15745.                   $param->getVersion() . '#' . $param->getGroup()])) {
  15746.                 $unset[] = $i;
  15747.             }
  15748.         }
  15749.         foreach ($unset as $i) {
  15750.             unset($params[$i]);
  15751.         }
  15752.         $ret = array();
  15753.         foreach ($params as $i => $param) {
  15754.             $ret[] = &$params[$i];
  15755.         }
  15756.         $params = array();
  15757.         foreach ($ret as $i => $param) {
  15758.             $params[] = &$ret[$i];
  15759.         }
  15760.     }
  15761.  
  15762.     function explicitState()
  15763.     {
  15764.         return $this->_explicitState;
  15765.     }
  15766.  
  15767.     function setExplicitState($s)
  15768.     {
  15769.         $this->_explicitState = $s;
  15770.     }
  15771.  
  15772.     /**
  15773.      * @static
  15774.      */
  15775.     function mergeDependencies(&$params)
  15776.     {
  15777.         $newparams = array();
  15778.         $bundles = array();
  15779.         foreach ($params as $i => $param) {
  15780.             if (!$param->isBundle()) {
  15781.                 continue;
  15782.             }
  15783.             $bundles[] = $i;
  15784.             $pf = &$param->getPackageFile();
  15785.             $newdeps = array();
  15786.             $contents = $pf->getBundledPackages();
  15787.             if (!is_array($contents)) {
  15788.                 $contents = array($contents);
  15789.             }
  15790.             foreach ($contents as $file) {
  15791.                 $filecontents = $pf->getFileContents($file);
  15792.                 $dl = &$param->getDownloader();
  15793.                 $options = $dl->getOptions();
  15794.                 if (PEAR::isError($dir = $dl->getDownloadDir())) {
  15795.                     return $dir;
  15796.                 }
  15797.                 $fp = @fopen($dir . DIRECTORY_SEPARATOR . $file, 'wb');
  15798.                 if (!$fp) {
  15799.                     continue;
  15800.                 }
  15801.                 fwrite($fp, $filecontents, strlen($filecontents));
  15802.                 fclose($fp);
  15803.                 if ($s = $params[$i]->explicitState()) {
  15804.                     $obj->setExplicitState($s);
  15805.                 }
  15806.                 $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
  15807.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15808.                 if (PEAR::isError($dir = $dl->getDownloadDir())) {
  15809.                     PEAR::popErrorHandling();
  15810.                     return $dir;
  15811.                 }
  15812.                 $e = $obj->_fromFile($a = $dir . DIRECTORY_SEPARATOR . $file);
  15813.                 PEAR::popErrorHandling();
  15814.                 if (PEAR::isError($e)) {
  15815.                     if (!isset($options['soft'])) {
  15816.                         $dl->log(0, $e->getMessage());
  15817.                     }
  15818.                     continue;
  15819.                 }
  15820.                 $j = &$obj;
  15821.                 if (!PEAR_Downloader_Package::willDownload($j,
  15822.                       array_merge($params, $newparams)) && !$param->isInstalled($j)) {
  15823.                     $newparams[] = &$j;
  15824.                 }
  15825.             }
  15826.         }
  15827.         foreach ($bundles as $i) {
  15828.             unset($params[$i]); // remove bundles - only their contents matter for installation
  15829.         }
  15830.         PEAR_Downloader_Package::removeDuplicates($params); // strip any unset indices
  15831.         if (count($newparams)) { // add in bundled packages for install
  15832.             foreach ($newparams as $i => $unused) {
  15833.                 $params[] = &$newparams[$i];
  15834.             }
  15835.             $newparams = array();
  15836.         }
  15837.         foreach ($params as $i => $param) {
  15838.             $newdeps = array();
  15839.             foreach ($param->_downloadDeps as $dep) {
  15840.                 if (!PEAR_Downloader_Package::willDownload($dep,
  15841.                       array_merge($params, $newparams)) && !$param->isInstalled($dep)) {
  15842.                     $newdeps[] = $dep;
  15843.                 } else {
  15844.                     // detect versioning conflicts here
  15845.                 }
  15846.             }
  15847.             // convert the dependencies into PEAR_Downloader_Package objects for the next time
  15848.             // around
  15849.             $params[$i]->_downloadDeps = array();
  15850.             foreach ($newdeps as $dep) {
  15851.                 $obj = &new PEAR_Downloader_Package($params[$i]->getDownloader());
  15852.                 if ($s = $params[$i]->explicitState()) {
  15853.                     $obj->setExplicitState($s);
  15854.                 }
  15855.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15856.                 $e = $obj->fromDepURL($dep);
  15857.                 PEAR::popErrorHandling();
  15858.                 if (PEAR::isError($e)) {
  15859.                     if (!isset($options['soft'])) {
  15860.                         $obj->_downloader->log(0, $e->getMessage());
  15861.                     }
  15862.                     continue;
  15863.                 }
  15864.                 $e = $obj->detectDependencies($params);
  15865.                 if (PEAR::isError($e)) {
  15866.                     if (!isset($options['soft'])) {
  15867.                         $obj->_downloader->log(0, $e->getMessage());
  15868.                     }
  15869.                 }
  15870.                 $j = &$obj;
  15871.                 $newparams[] = &$j;
  15872.             }
  15873.         }
  15874.         if (count($newparams)) {
  15875.             foreach ($newparams as $i => $unused) {
  15876.                 $params[] = &$newparams[$i];
  15877.             }
  15878.             return true;
  15879.         } else {
  15880.             return false;
  15881.         }
  15882.     }
  15883.  
  15884.  
  15885.     /**
  15886.      * @static
  15887.      */
  15888.     function willDownload($param, $params)
  15889.     {
  15890.         if (!is_array($params)) {
  15891.             return false;
  15892.         }
  15893.         foreach ($params as $obj) {
  15894.             if ($obj->isEqual($param)) {
  15895.                 return true;
  15896.             }
  15897.         }
  15898.         return false;
  15899.     }
  15900.  
  15901.     /**
  15902.      * For simpler unit-testing
  15903.      * @param PEAR_Config
  15904.      * @param int
  15905.      * @param string
  15906.      */
  15907.     function &getPackagefileObject(&$c, $d, $t = false)
  15908.     {
  15909.         $a = &new PEAR_PackageFile($c, $d, $t);
  15910.         return $a;
  15911.     }
  15912.  
  15913.  
  15914.     /**
  15915.      * This will retrieve from a local file if possible, and parse out
  15916.      * a group name as well.  The original parameter will be modified to reflect this.
  15917.      * @param string|array can be a parsed package name as well
  15918.      * @access private
  15919.      */
  15920.     function _fromFile(&$param)
  15921.     {
  15922.         $saveparam = $param;
  15923.         if (is_string($param)) {
  15924.             if (!@file_exists($param)) {
  15925.                 $test = explode('#', $param);
  15926.                 $group = array_pop($test);
  15927.                 if (file_exists(implode('#', $test))) {
  15928.                     $this->setGroup($group);
  15929.                     $param = implode('#', $test);
  15930.                     $this->_explicitGroup = true;
  15931.                 }
  15932.             }
  15933.             if (@is_file($param)) {
  15934.                 $this->_type = 'local';
  15935.                 $options = $this->_downloader->getOptions();
  15936.                 if (isset($options['downloadonly'])) {
  15937.                     $pkg = &$this->getPackagefileObject($this->_config,
  15938.                         $this->_downloader->_debug);
  15939.                 } else {
  15940.                     if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  15941.                         return $dir;
  15942.                     }
  15943.                     $pkg = &$this->getPackagefileObject($this->_config,
  15944.                         $this->_downloader->_debug, $dir);
  15945.                 }
  15946.                 PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  15947.                 $pf = &$pkg->fromAnyFile($param, PEAR_VALIDATE_INSTALLING);
  15948.                 PEAR::popErrorHandling();
  15949.                 if (PEAR::isError($pf)) {
  15950.                     $this->_valid = false;
  15951.                     $param = $saveparam;
  15952.                     return $pf;
  15953.                 }
  15954.                 $this->_packagefile = &$pf;
  15955.                 if (!$this->getGroup()) {
  15956.                     $this->setGroup('default'); // install the default dependency group
  15957.                 }
  15958.                 return $this->_valid = true;
  15959.             }
  15960.         }
  15961.         $param = $saveparam;
  15962.         return $this->_valid = false;
  15963.     }
  15964.  
  15965.     function _fromUrl($param, $saveparam = '')
  15966.     {
  15967.         if (!is_array($param) &&
  15968.               (preg_match('#^(http|ftp)://#', $param))) {
  15969.             $options = $this->_downloader->getOptions();
  15970.             $this->_type = 'url';
  15971.             $callback = $this->_downloader->ui ?
  15972.                 array(&$this->_downloader, '_downloadCallback') : null;
  15973.             $this->_downloader->pushErrorHandling(PEAR_ERROR_RETURN);
  15974.             if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  15975.                 $this->_downloader->popErrorHandling();
  15976.                 return $dir;
  15977.             }
  15978.             $file = $this->_downloader->downloadHttp($param, $this->_downloader->ui,
  15979.                 $dir, $callback);
  15980.             $this->_downloader->popErrorHandling();
  15981.             if (PEAR::isError($file)) {
  15982.                 if (!empty($saveparam)) {
  15983.                     $saveparam = ", cannot download \"$saveparam\"";
  15984.                 }
  15985.                 $err = PEAR::raiseError('Could not download from "' . $param .
  15986.                     '"' . $saveparam . ' (' . $file->getMessage() . ')');
  15987.                     return $err;
  15988.             }
  15989.             if ($this->_rawpackagefile) {
  15990.                 require_once 'phar://go-pear.phar/Archive/Tar.php';
  15991.                 $tar = &new Archive_Tar($file);
  15992.                 $packagexml = $tar->extractInString('package2.xml');
  15993.                 if (!$packagexml) {
  15994.                     $packagexml = $tar->extractInString('package.xml');
  15995.                 }
  15996.                 if (str_replace(array("\n", "\r"), array('',''), $packagexml) !=
  15997.                       str_replace(array("\n", "\r"), array('',''), $this->_rawpackagefile)) {
  15998.                     if ($this->getChannel() == 'pear.php.net') {
  15999.                         // be more lax for the existing PEAR packages that have not-ok
  16000.                         // characters in their package.xml
  16001.                         $this->_downloader->log(0, 'CRITICAL WARNING: The "' .
  16002.                             $this->getPackage() . '" package has invalid characters in its ' .
  16003.                             'package.xml.  The next version of PEAR may not be able to install ' .
  16004.                             'this package for security reasons.  Please open a bug report at ' .
  16005.                             'http://pear.php.net/package/' . $this->getPackage() . '/bugs');
  16006.                     } else {
  16007.                         return PEAR::raiseError('CRITICAL ERROR: package.xml downloaded does ' .
  16008.                             'not match value returned from xml-rpc');
  16009.                     }
  16010.                 }
  16011.             }
  16012.             // whew, download worked!
  16013.             if (isset($options['downloadonly'])) {
  16014.                 $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug);
  16015.             } else {
  16016.                 if (PEAR::isError($dir = $this->_downloader->getDownloadDir())) {
  16017.                     return $dir;
  16018.                 }
  16019.                 $pkg = &$this->getPackagefileObject($this->_config, $this->_downloader->debug,
  16020.                     $dir);
  16021.             }
  16022.             PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16023.             $pf = &$pkg->fromAnyFile($file, PEAR_VALIDATE_INSTALLING);
  16024.             PEAR::popErrorHandling();
  16025.             if (PEAR::isError($pf)) {
  16026.                 if (is_array($pf->getUserInfo())) {
  16027.                     foreach ($pf->getUserInfo() as $err) {
  16028.                         if (is_array($err)) {
  16029.                             $err = $err['message'];
  16030.                         }
  16031.                         if (!isset($options['soft'])) {
  16032.                             $this->_downloader->log(0, "Validation Error: $err");
  16033.                         }
  16034.                     }
  16035.                 }
  16036.                 if (!isset($options['soft'])) {
  16037.                     $this->_downloader->log(0, $pf->getMessage());
  16038.                 }
  16039.                 $err = PEAR::raiseError('Download of "' . ($saveparam ? $saveparam :
  16040.                     $param) . '" succeeded, but it is not a valid package archive');
  16041.                 $this->_valid = false;
  16042.                 return $err;
  16043.             }
  16044.             $this->_packagefile = &$pf;
  16045.             $this->setGroup('default'); // install the default dependency group
  16046.             return $this->_valid = true;
  16047.         }
  16048.         return $this->_valid = false;
  16049.     }
  16050.  
  16051.     /**
  16052.      *
  16053.      * @param string|array pass in an array of format
  16054.      *                     array(
  16055.      *                      'package' => 'pname',
  16056.      *                     ['channel' => 'channame',]
  16057.      *                     ['version' => 'version',]
  16058.      *                     ['state' => 'state',])
  16059.      *                     or a string of format [channame/]pname[-version|-state]
  16060.      */
  16061.     function _fromString($param)
  16062.     {
  16063.         $options = $this->_downloader->getOptions();
  16064.         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16065.         $pname = $this->_registry->parsePackageName($param,
  16066.             $this->_config->get('default_channel'));
  16067.         PEAR::popErrorHandling();
  16068.         if (PEAR::isError($pname)) {
  16069.             if ($pname->getCode() == 'invalid') {
  16070.                 $this->_valid = false;
  16071.                 return false;
  16072.             }
  16073.             if ($pname->getCode() == 'channel') {
  16074.                 $parsed = $pname->getUserInfo();
  16075.                 if ($this->_downloader->discover($parsed['channel'])) {
  16076.                     if ($this->_config->get('auto_discover')) {
  16077.                         PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
  16078.                         $pname = $this->_registry->parsePackageName($param,
  16079.                             $this->_config->get('default_channel'));
  16080.                         PEAR::popErrorHandling();
  16081.                     } else {
  16082.                         if (!isset($options['soft'])) {
  16083.                             $this->_downloader->log(0, 'Channel "' . $parsed['channel'] .
  16084.                                 '" is not initialized, use ' .
  16085.                                 '"pear channel-discover ' . $parsed['channel'] . '" to initialize' .
  16086.                                 'or pear config-set auto_discover 1');
  16087.                         }
  16088.                     }
  16089.                 }
  16090.                 if (PEAR::isError($pname)) {
  16091.                     if (!isset($options['soft'])) {
  16092.                         $this->_downloader->log(0, $pname->getMessage());
  16093.                     }
  16094.                     if (is_array($param)) {
  16095.                         $param = $this->_registry->parsedPackageNameToString($param);
  16096.                     }
  16097.                     $err = PEAR::raiseError('invalid package name/package file "' .
  16098.                         $param . '"');
  16099.                     $this->_valid = false;
  16100.                     return $err;
  16101.                 }
  16102.             } else {
  16103.                 if (!isset($options['soft'])) {
  16104.                     $this->_downloader->log(0, $pname->getMessage());
  16105.                 }
  16106.                 $err = PEAR::raiseError('invalid package name/package file "' .
  16107.                     $param . '"');
  16108.                 $this->_valid = false;
  16109.                 return $err;
  16110.             }
  16111.         }
  16112.         if (!isset($this->_type)) {
  16113.             $this->_type = 'xmlrpc';
  16114.         }
  16115.         $this->_parsedname = $pname;
  16116.         if (isset($pname['state'])) {
  16117.             $this->_explicitState = $pname['state'];
  16118.         } else {
  16119.             $this->_explicitState = false;
  16120.         }
  16121.         if (isset($pname['group'])) {
  16122.             $this->_explicitGroup = true;
  16123.         } else {
  16124.             $this->_explicitGroup = false;
  16125.         }
  16126.         $info = $this->_downloader->_getPackageDownloadUrl($pname);
  16127.         if (PEAR::isError($info)) {
  16128.             if ($info->getCode() != -976 && $pname['channel'] == 'pear.php.net') {
  16129.                 // try pecl
  16130.                 $pname['channel'] = 'pecl.php.net';
  16131.                 if ($test = $this->_downloader->_getPackageDownloadUrl($pname)) {
  16132.                     if (!PEAR::isError($test)) {
  16133.                         $info = PEAR::raiseError($info->getMessage() . ' - package ' .
  16134.                             $this->_registry->parsedPackageNameToString($pname, true) .
  16135.                             ' can be installed with "pecl install ' . $pname['package'] .
  16136.                             '"');
  16137.                     } else {
  16138.                         $pname['channel'] = 'pear.php.net';
  16139.                     }
  16140.                 } else {
  16141.                     $pname['channel'] = 'pear.php.net';
  16142.                 }
  16143.             }
  16144.             return $info;
  16145.         }
  16146.         $this->_rawpackagefile = $info['raw'];
  16147.         $ret = $this->_analyzeDownloadURL($info, $param, $pname);
  16148.         if (PEAR::isError($ret)) {
  16149.             return $ret;
  16150.         }
  16151.         if ($ret) {
  16152.             $this->_downloadURL = $ret;
  16153.             return $this->_valid = (bool) $ret;
  16154.         }
  16155.     }
  16156.  
  16157.     /**
  16158.      * @param array output of package.getDownloadURL
  16159.      * @param string|array|object information for detecting packages to be downloaded, and
  16160.      *                            for errors
  16161.      * @param array name information of the package
  16162.      * @param array|null packages to be downloaded
  16163.      * @param bool is this an optional dependency?
  16164.      * @param bool is this any kind of dependency?
  16165.      * @access private
  16166.      */
  16167.     function _analyzeDownloadURL($info, $param, $pname, $params = null, $optional = false,
  16168.                                  $isdependency = false)
  16169.     {
  16170.         if (!is_string($param) && PEAR_Downloader_Package::willDownload($param, $params)) {
  16171.             return false;
  16172.         }
  16173.         if (!$info) {
  16174.             if (!is_string($param)) {
  16175.                 $saveparam = ", cannot download \"$param\"";
  16176.             } else {
  16177.                 $saveparam = '';
  16178.             }
  16179.             // no releases exist
  16180.             return PEAR::raiseError('No releases for package "' .
  16181.                 $this->_registry->parsedPackageNameToString($pname, true) . '" exist' . $saveparam);
  16182.         }
  16183.         if (strtolower($info['info']->getChannel()) != strtolower($pname['channel'])) {
  16184.             $err = false;
  16185.             if ($pname['channel'] == 'pecl.php.net') {
  16186.                 if ($info['info']->getChannel() != 'pear.php.net') {
  16187.                     $err = true;
  16188.                 }
  16189.             } elseif ($info['info']->getChannel() == 'pecl.php.net') {
  16190.                 if ($pname['channel'] != 'pear.php.net') {
  16191.                     $err = true;
  16192.                 }
  16193.             } else {
  16194.                 $err = true;
  16195.             }
  16196.             if ($err) {
  16197.                 return PEAR::raiseError('SECURITY ERROR: package in channel "' . $pname['channel'] .
  16198.                     '" retrieved another channel\'s name for download! ("' .
  16199.                     $info['info']->getChannel() . '")');
  16200.             }
  16201.         }
  16202.         if (!isset($info['url'])) {
  16203.             if ($this->isInstalled($info)) {
  16204.                 if ($isdependency && version_compare($info['version'],
  16205.                       $this->_registry->packageInfo($info['info']->getPackage(),
  16206.                             'version', $info['info']->getChannel()), '<=')) {
  16207.                     // ignore bogus errors of "failed to download dependency"
  16208.                     // if it is already installed and the one that would be
  16209.                     // downloaded is older or the same version (Bug #7219)
  16210.                     return false;
  16211.                 }
  16212.             }
  16213.             $instead =  ', will instead download version ' . $info['version'] .
  16214.                         ', stability "' . $info['info']->getState() . '"';
  16215.             // releases exist, but we failed to get any
  16216.             if (isset($this->_downloader->_options['force'])) {
  16217.                 if (isset($pname['version'])) {
  16218.                     $vs = ', version "' . $pname['version'] . '"';
  16219.                 } elseif (isset($pname['state'])) {
  16220.                     $vs = ', stability "' . $pname['state'] . '"';
  16221.                 } elseif ($param == 'dependency') {
  16222.                     if (!class_exists('PEAR_Common')) {
  16223.                         require_once 'phar://go-pear.phar/PEAR/Common.php';
  16224.                     }
  16225.                     if (!in_array($info['info']->getState(),
  16226.                           PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
  16227.                         if ($optional) {
  16228.                             // don't spit out confusing error message
  16229.                             return $this->_downloader->_getPackageDownloadUrl(
  16230.                                 array('package' => $pname['package'],
  16231.                                       'channel' => $pname['channel'],
  16232.                                       'version' => $info['version']));
  16233.                         }
  16234.                         $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
  16235.                             '"';
  16236.                     } else {
  16237.                         if (!class_exists('PEAR_Dependency2')) {
  16238.                             require_once 'phar://go-pear.phar/PEAR/Dependency2.php';
  16239.                         }
  16240.                         if ($optional) {
  16241.                             // don't spit out confusing error message
  16242.                             return $this->_downloader->_getPackageDownloadUrl(
  16243.                                 array('package' => $pname['package'],
  16244.                                       'channel' => $pname['channel'],
  16245.                                       'version' => $info['version']));
  16246.                         }
  16247.                         $vs = PEAR_Dependency2::_getExtraString($pname);
  16248.                         $instead = '';
  16249.                     }
  16250.                 } else {
  16251.                     $vs = ' within preferred state "' . $this->_config->get(
  16252.                         'preferred_state') . '"';
  16253.                 }
  16254.                 if (!isset($options['soft'])) {
  16255.                     $this->_downloader->log(1, 'WARNING: failed to download ' . $pname['channel'] .
  16256.                         '/' . $pname['package'] . $vs . $instead);
  16257.                 }
  16258.                 // download the latest release
  16259.                 return $this->_downloader->_getPackageDownloadUrl(
  16260.                     array('package' => $pname['package'],
  16261.                           'channel' => $pname['channel'],
  16262.                           'version' => $info['version']));
  16263.             } else {
  16264.                 // construct helpful error message
  16265.                 if (isset($pname['version'])) {
  16266.                     $vs = ', version "' . $pname['version'] . '"';
  16267.                 } elseif (isset($pname['state'])) {
  16268.                     $vs = ', stability "' . $pname['state'] . '"';
  16269.                 } elseif ($param == 'dependency') {
  16270.                     if (!class_exists('PEAR_Common')) {
  16271.                         require_once 'phar://go-pear.phar/PEAR/Common.php';
  16272.                     }
  16273.                     if (!in_array($info['info']->getState(),
  16274.                           PEAR_Common::betterStates($this->_config->get('preferred_state'), true))) {
  16275.                         if ($optional) {
  16276.                             // don't spit out confusing error message, and don't die on
  16277.                             // optional dep failure!
  16278.                             return $this->_downloader->_getPackageDownloadUrl(
  16279.                                 array('package' => $pname['package'],
  16280.                                       'channel' => $pname['channel'],
  16281.                                       'version' => $info['version']));
  16282.                         }
  16283.                         $vs = ' within preferred state "' . $this->_config->get('preferred_state') .
  16284.                             '"';
  16285.                     } else {
  16286.                         if (!class_exists('PEAR_Dependency2')) {
  16287.                             require_once 'phar://go-pear.phar/PEAR/Dependency2.php';
  16288.                         }
  16289.                         if ($optional) {
  16290.                             // don't spit out confusing error message, and don't die on
  16291.                             // optional dep failure!
  16292.                             return $this->_downloader->_getPackageDownloadUrl(
  16293.                                 array('package' => $pname['package'],
  16294.                                       'channel' => $pname['channel'],
  16295.                                       'version' => $info['version']));
  16296.                         }
  16297.                         $vs = PEAR_Dependency2::_getExtraString($pname);
  16298.                     }
  16299.                 } else {
  16300.                     $vs = ' within preferred state "' . $this->_downloader->config->get(
  16301.                         'preferred_state') . '"';
  16302.                 }
  16303.                 $options = $this->_downloader->getOptions();
  16304.                 // this is only set by the "download-all" command
  16305.                 if (isset($options['ignorepreferred_state'])) {
  16306.                     $err = PEAR::raiseError(
  16307.                         'Failed to download ' . $this->_registry->parsedPackageNameToString(
  16308.                             array('channel' => $pname['channel'], 'package' => $pname['package']),
  16309.                                 true)
  16310.                          . $vs .
  16311.                         ', latest release is version ' . $info['version'] .
  16312.                         ', stability "' . $info['info']->getState() . '", use "' .
  16313.                         $this->_registry->parsedPackageNameToString(
  16314.                             array('channel' => $pname['channel'], 'package' => $pname['package'],
  16315.                             'version' => $info['version'])) . '" to install',
  16316.                             PEAR_DOWNLOADER_PACKAGE_STATE);
  16317.                     return $err;
  16318.                 }
  16319.                 $err = PEAR::raiseError(
  16320.                     'Failed to download ' . $this->_registry->parsedPackageNameToString(
  16321.                         array('channel' => $pname['channel'], 'package' => $pname['package']),
  16322.                             true)
  16323.                      . $vs .
  16324.                     ', latest release is version ' . $info['version'] .
  16325.                     ', stability "' . $info['info']->getState() . '", use "' .
  16326.                     $this->_registry->parsedPackageNameToString(
  16327.                         array('channel' => $pname['channel'], 'package' => $pname['package'],
  16328.                         'version' => $info['version'])) . '" to install');
  16329.                 return $err;
  16330.             }
  16331.         }
  16332.         if (isset($info['deprecated']) && $info['deprecated']) {
  16333.             $this->_downloader->log(0,
  16334.                 'WARNING: "' . 
  16335.                     $this->_registry->parsedPackageNameToString(
  16336.                             array('channel' => $info['info']->getChannel(),
  16337.                                   'package' => $info['info']->getPackage()), true) .
  16338.                 '" is deprecated in favor of "' .
  16339.                     $this->_registry->parsedPackageNameToString($info['deprecated'], true) .
  16340.                 '"');
  16341.         }
  16342.         return $info;
  16343.     }
  16344. }
  16345. ?>
  16346. <?php
  16347. /**
  16348.  * Error Stack Implementation
  16349.  * 
  16350.  * This is an incredibly simple implementation of a very complex error handling
  16351.  * facility.  It contains the ability
  16352.  * to track multiple errors from multiple packages simultaneously.  In addition,
  16353.  * it can track errors of many levels, save data along with the error, context
  16354.  * information such as the exact file, line number, class and function that
  16355.  * generated the error, and if necessary, it can raise a traditional PEAR_Error.
  16356.  * It has built-in support for PEAR::Log, to log errors as they occur
  16357.  * 
  16358.  * Since version 0.2alpha, it is also possible to selectively ignore errors,
  16359.  * through the use of an error callback, see {@link pushCallback()}
  16360.  * 
  16361.  * Since version 0.3alpha, it is possible to specify the exception class
  16362.  * returned from {@link push()}
  16363.  *
  16364.  * Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class.  This can
  16365.  * still be done quite handily in an error callback or by manipulating the returned array
  16366.  * @category   Debugging
  16367.  * @package    PEAR_ErrorStack
  16368.  * @author     Greg Beaver <cellog@php.net>
  16369.  * @copyright  2004-2006 Greg Beaver
  16370.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  16371.  * @version    CVS: $Id: ErrorStack.php,v 1.25 2006/09/22 03:13:17 cellog Exp $
  16372.  * @link       http://pear.php.net/package/PEAR_ErrorStack
  16373.  */
  16374.  
  16375. /**
  16376.  * Singleton storage
  16377.  * 
  16378.  * Format:
  16379.  * <pre>
  16380.  * array(
  16381.  *  'package1' => PEAR_ErrorStack object,
  16382.  *  'package2' => PEAR_ErrorStack object,
  16383.  *  ...
  16384.  * )
  16385.  * </pre>
  16386.  * @access private
  16387.  * @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
  16388.  */
  16389. $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
  16390.  
  16391. /**
  16392.  * Global error callback (default)
  16393.  * 
  16394.  * This is only used if set to non-false.  * is the default callback for
  16395.  * all packages, whereas specific packages may set a default callback
  16396.  * for all instances, regardless of whether they are a singleton or not.
  16397.  *
  16398.  * To exclude non-singletons, only set the local callback for the singleton
  16399.  * @see PEAR_ErrorStack::setDefaultCallback()
  16400.  * @access private
  16401.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
  16402.  */
  16403. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
  16404.     '*' => false,
  16405. );
  16406.  
  16407. /**
  16408.  * Global Log object (default)
  16409.  * 
  16410.  * This is only used if set to non-false.  Use to set a default log object for
  16411.  * all stacks, regardless of instantiation order or location
  16412.  * @see PEAR_ErrorStack::setDefaultLogger()
  16413.  * @access private
  16414.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  16415.  */
  16416. $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
  16417.  
  16418. /**
  16419.  * Global Overriding Callback
  16420.  * 
  16421.  * This callback will override any error callbacks that specific loggers have set.
  16422.  * Use with EXTREME caution
  16423.  * @see PEAR_ErrorStack::staticPushCallback()
  16424.  * @access private
  16425.  * @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
  16426.  */
  16427. $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  16428.  
  16429. /**#@+
  16430.  * One of four possible return values from the error Callback
  16431.  * @see PEAR_ErrorStack::_errorCallback()
  16432.  */
  16433. /**
  16434.  * If this is returned, then the error will be both pushed onto the stack
  16435.  * and logged.
  16436.  */
  16437. define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
  16438. /**
  16439.  * If this is returned, then the error will only be pushed onto the stack,
  16440.  * and not logged.
  16441.  */
  16442. define('PEAR_ERRORSTACK_PUSH', 2);
  16443. /**
  16444.  * If this is returned, then the error will only be logged, but not pushed
  16445.  * onto the error stack.
  16446.  */
  16447. define('PEAR_ERRORSTACK_LOG', 3);
  16448. /**
  16449.  * If this is returned, then the error is completely ignored.
  16450.  */
  16451. define('PEAR_ERRORSTACK_IGNORE', 4);
  16452. /**
  16453.  * If this is returned, then the error is logged and die() is called.
  16454.  */
  16455. define('PEAR_ERRORSTACK_DIE', 5);
  16456. /**#@-*/
  16457.  
  16458. /**
  16459.  * Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
  16460.  * the singleton method.
  16461.  */
  16462. define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
  16463.  
  16464. /**
  16465.  * Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
  16466.  * that has no __toString() method
  16467.  */
  16468. define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
  16469. /**
  16470.  * Error Stack Implementation
  16471.  *
  16472.  * Usage:
  16473.  * <code>
  16474.  * // global error stack
  16475.  * $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
  16476.  * // local error stack
  16477.  * $local_stack = new PEAR_ErrorStack('MyPackage');
  16478.  * </code>
  16479.  * @author     Greg Beaver <cellog@php.net>
  16480.  * @version    @package_version@
  16481.  * @package    PEAR_ErrorStack
  16482.  * @category   Debugging
  16483.  * @copyright  2004-2006 Greg Beaver
  16484.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  16485.  * @version    CVS: $Id: ErrorStack.php,v 1.25 2006/09/22 03:13:17 cellog Exp $
  16486.  * @link       http://pear.php.net/package/PEAR_ErrorStack
  16487.  */
  16488. class PEAR_ErrorStack {
  16489.     /**
  16490.      * Errors are stored in the order that they are pushed on the stack.
  16491.      * @since 0.4alpha Errors are no longer organized by error level.
  16492.      * This renders pop() nearly unusable, and levels could be more easily
  16493.      * handled in a callback anyway
  16494.      * @var array
  16495.      * @access private
  16496.      */
  16497.     var $_errors = array();
  16498.  
  16499.     /**
  16500.      * Storage of errors by level.
  16501.      *
  16502.      * Allows easy retrieval and deletion of only errors from a particular level
  16503.      * @since PEAR 1.4.0dev
  16504.      * @var array
  16505.      * @access private
  16506.      */
  16507.     var $_errorsByLevel = array();
  16508.  
  16509.     /**
  16510.      * Package name this error stack represents
  16511.      * @var string
  16512.      * @access protected
  16513.      */
  16514.     var $_package;
  16515.     
  16516.     /**
  16517.      * Determines whether a PEAR_Error is thrown upon every error addition
  16518.      * @var boolean
  16519.      * @access private
  16520.      */
  16521.     var $_compat = false;
  16522.     
  16523.     /**
  16524.      * If set to a valid callback, this will be used to generate the error
  16525.      * message from the error code, otherwise the message passed in will be
  16526.      * used
  16527.      * @var false|string|array
  16528.      * @access private
  16529.      */
  16530.     var $_msgCallback = false;
  16531.     
  16532.     /**
  16533.      * If set to a valid callback, this will be used to generate the error
  16534.      * context for an error.  For PHP-related errors, this will be a file
  16535.      * and line number as retrieved from debug_backtrace(), but can be
  16536.      * customized for other purposes.  The error might actually be in a separate
  16537.      * configuration file, or in a database query.
  16538.      * @var false|string|array
  16539.      * @access protected
  16540.      */
  16541.     var $_contextCallback = false;
  16542.     
  16543.     /**
  16544.      * If set to a valid callback, this will be called every time an error
  16545.      * is pushed onto the stack.  The return value will be used to determine
  16546.      * whether to allow an error to be pushed or logged.
  16547.      * 
  16548.      * The return value must be one an PEAR_ERRORSTACK_* constant
  16549.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  16550.      * @var false|string|array
  16551.      * @access protected
  16552.      */
  16553.     var $_errorCallback = array();
  16554.     
  16555.     /**
  16556.      * PEAR::Log object for logging errors
  16557.      * @var false|Log
  16558.      * @access protected
  16559.      */
  16560.     var $_logger = false;
  16561.     
  16562.     /**
  16563.      * Error messages - designed to be overridden
  16564.      * @var array
  16565.      * @abstract
  16566.      */
  16567.     var $_errorMsgs = array();
  16568.     
  16569.     /**
  16570.      * Set up a new error stack
  16571.      * 
  16572.      * @param string   $package name of the package this error stack represents
  16573.      * @param callback $msgCallback callback used for error message generation
  16574.      * @param callback $contextCallback callback used for context generation,
  16575.      *                 defaults to {@link getFileLine()}
  16576.      * @param boolean  $throwPEAR_Error
  16577.      */
  16578.     function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
  16579.                          $throwPEAR_Error = false)
  16580.     {
  16581.         $this->_package = $package;
  16582.         $this->setMessageCallback($msgCallback);
  16583.         $this->setContextCallback($contextCallback);
  16584.         $this->_compat = $throwPEAR_Error;
  16585.     }
  16586.     
  16587.     /**
  16588.      * Return a single error stack for this package.
  16589.      * 
  16590.      * Note that all parameters are ignored if the stack for package $package
  16591.      * has already been instantiated
  16592.      * @param string   $package name of the package this error stack represents
  16593.      * @param callback $msgCallback callback used for error message generation
  16594.      * @param callback $contextCallback callback used for context generation,
  16595.      *                 defaults to {@link getFileLine()}
  16596.      * @param boolean  $throwPEAR_Error
  16597.      * @param string   $stackClass class to instantiate
  16598.      * @static
  16599.      * @return PEAR_ErrorStack
  16600.      */
  16601.     function &singleton($package, $msgCallback = false, $contextCallback = false,
  16602.                          $throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack')
  16603.     {
  16604.         if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  16605.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  16606.         }
  16607.         if (!class_exists($stackClass)) {
  16608.             if (function_exists('debug_backtrace')) {
  16609.                 $trace = debug_backtrace();
  16610.             }
  16611.             PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
  16612.                 'exception', array('stackclass' => $stackClass),
  16613.                 'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
  16614.                 false, $trace);
  16615.         }
  16616.         $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
  16617.             new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
  16618.  
  16619.         return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
  16620.     }
  16621.  
  16622.     /**
  16623.      * Internal error handler for PEAR_ErrorStack class
  16624.      * 
  16625.      * Dies if the error is an exception (and would have died anyway)
  16626.      * @access private
  16627.      */
  16628.     function _handleError($err)
  16629.     {
  16630.         if ($err['level'] == 'exception') {
  16631.             $message = $err['message'];
  16632.             if (isset($_SERVER['REQUEST_URI'])) {
  16633.                 echo '<br />';
  16634.             } else {
  16635.                 echo "\n";
  16636.             }
  16637.             var_dump($err['context']);
  16638.             die($message);
  16639.         }
  16640.     }
  16641.     
  16642.     /**
  16643.      * Set up a PEAR::Log object for all error stacks that don't have one
  16644.      * @param Log $log 
  16645.      * @static
  16646.      */
  16647.     function setDefaultLogger(&$log)
  16648.     {
  16649.         if (is_object($log) && method_exists($log, 'log') ) {
  16650.             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  16651.         } elseif (is_callable($log)) {
  16652.             $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
  16653.     }
  16654.     }
  16655.     
  16656.     /**
  16657.      * Set up a PEAR::Log object for this error stack
  16658.      * @param Log $log 
  16659.      */
  16660.     function setLogger(&$log)
  16661.     {
  16662.         if (is_object($log) && method_exists($log, 'log') ) {
  16663.             $this->_logger = &$log;
  16664.         } elseif (is_callable($log)) {
  16665.             $this->_logger = &$log;
  16666.         }
  16667.     }
  16668.     
  16669.     /**
  16670.      * Set an error code => error message mapping callback
  16671.      * 
  16672.      * This method sets the callback that can be used to generate error
  16673.      * messages for any instance
  16674.      * @param array|string Callback function/method
  16675.      */
  16676.     function setMessageCallback($msgCallback)
  16677.     {
  16678.         if (!$msgCallback) {
  16679.             $this->_msgCallback = array(&$this, 'getErrorMessage');
  16680.         } else {
  16681.             if (is_callable($msgCallback)) {
  16682.                 $this->_msgCallback = $msgCallback;
  16683.             }
  16684.         }
  16685.     }
  16686.     
  16687.     /**
  16688.      * Get an error code => error message mapping callback
  16689.      * 
  16690.      * This method returns the current callback that can be used to generate error
  16691.      * messages
  16692.      * @return array|string|false Callback function/method or false if none
  16693.      */
  16694.     function getMessageCallback()
  16695.     {
  16696.         return $this->_msgCallback;
  16697.     }
  16698.     
  16699.     /**
  16700.      * Sets a default callback to be used by all error stacks
  16701.      * 
  16702.      * This method sets the callback that can be used to generate error
  16703.      * messages for a singleton
  16704.      * @param array|string Callback function/method
  16705.      * @param string Package name, or false for all packages
  16706.      * @static
  16707.      */
  16708.     function setDefaultCallback($callback = false, $package = false)
  16709.     {
  16710.         if (!is_callable($callback)) {
  16711.             $callback = false;
  16712.         }
  16713.         $package = $package ? $package : '*';
  16714.         $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
  16715.     }
  16716.     
  16717.     /**
  16718.      * Set a callback that generates context information (location of error) for an error stack
  16719.      * 
  16720.      * This method sets the callback that can be used to generate context
  16721.      * information for an error.  Passing in NULL will disable context generation
  16722.      * and remove the expensive call to debug_backtrace()
  16723.      * @param array|string|null Callback function/method
  16724.      */
  16725.     function setContextCallback($contextCallback)
  16726.     {
  16727.         if ($contextCallback === null) {
  16728.             return $this->_contextCallback = false;
  16729.         }
  16730.         if (!$contextCallback) {
  16731.             $this->_contextCallback = array(&$this, 'getFileLine');
  16732.         } else {
  16733.             if (is_callable($contextCallback)) {
  16734.                 $this->_contextCallback = $contextCallback;
  16735.             }
  16736.         }
  16737.     }
  16738.     
  16739.     /**
  16740.      * Set an error Callback
  16741.      * If set to a valid callback, this will be called every time an error
  16742.      * is pushed onto the stack.  The return value will be used to determine
  16743.      * whether to allow an error to be pushed or logged.
  16744.      * 
  16745.      * The return value must be one of the ERRORSTACK_* constants.
  16746.      * 
  16747.      * This functionality can be used to emulate PEAR's pushErrorHandling, and
  16748.      * the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
  16749.      * the error stack or logging
  16750.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  16751.      * @see popCallback()
  16752.      * @param string|array $cb
  16753.      */
  16754.     function pushCallback($cb)
  16755.     {
  16756.         array_push($this->_errorCallback, $cb);
  16757.     }
  16758.     
  16759.     /**
  16760.      * Remove a callback from the error callback stack
  16761.      * @see pushCallback()
  16762.      * @return array|string|false
  16763.      */
  16764.     function popCallback()
  16765.     {
  16766.         if (!count($this->_errorCallback)) {
  16767.             return false;
  16768.         }
  16769.         return array_pop($this->_errorCallback);
  16770.     }
  16771.     
  16772.     /**
  16773.      * Set a temporary overriding error callback for every package error stack
  16774.      *
  16775.      * Use this to temporarily disable all existing callbacks (can be used
  16776.      * to emulate the @ operator, for instance)
  16777.      * @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
  16778.      * @see staticPopCallback(), pushCallback()
  16779.      * @param string|array $cb
  16780.      * @static
  16781.      */
  16782.     function staticPushCallback($cb)
  16783.     {
  16784.         array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
  16785.     }
  16786.     
  16787.     /**
  16788.      * Remove a temporary overriding error callback
  16789.      * @see staticPushCallback()
  16790.      * @return array|string|false
  16791.      * @static
  16792.      */
  16793.     function staticPopCallback()
  16794.     {
  16795.         $ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
  16796.         if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
  16797.             $GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
  16798.         }
  16799.         return $ret;
  16800.     }
  16801.     
  16802.     /**
  16803.      * Add an error to the stack
  16804.      * 
  16805.      * If the message generator exists, it is called with 2 parameters.
  16806.      *  - the current Error Stack object
  16807.      *  - an array that is in the same format as an error.  Available indices
  16808.      *    are 'code', 'package', 'time', 'params', 'level', and 'context'
  16809.      * 
  16810.      * Next, if the error should contain context information, this is
  16811.      * handled by the context grabbing method.
  16812.      * Finally, the error is pushed onto the proper error stack
  16813.      * @param int    $code      Package-specific error code
  16814.      * @param string $level     Error level.  This is NOT spell-checked
  16815.      * @param array  $params    associative array of error parameters
  16816.      * @param string $msg       Error message, or a portion of it if the message
  16817.      *                          is to be generated
  16818.      * @param array  $repackage If this error re-packages an error pushed by
  16819.      *                          another package, place the array returned from
  16820.      *                          {@link pop()} in this parameter
  16821.      * @param array  $backtrace Protected parameter: use this to pass in the
  16822.      *                          {@link debug_backtrace()} that should be used
  16823.      *                          to find error context
  16824.      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  16825.      * thrown.  If a PEAR_Error is returned, the userinfo
  16826.      * property is set to the following array:
  16827.      * 
  16828.      * <code>
  16829.      * array(
  16830.      *    'code' => $code,
  16831.      *    'params' => $params,
  16832.      *    'package' => $this->_package,
  16833.      *    'level' => $level,
  16834.      *    'time' => time(),
  16835.      *    'context' => $context,
  16836.      *    'message' => $msg,
  16837.      * //['repackage' => $err] repackaged error array/Exception class
  16838.      * );
  16839.      * </code>
  16840.      * 
  16841.      * Normally, the previous array is returned.
  16842.      */
  16843.     function push($code, $level = 'error', $params = array(), $msg = false,
  16844.                   $repackage = false, $backtrace = false)
  16845.     {
  16846.         $context = false;
  16847.         // grab error context
  16848.         if ($this->_contextCallback) {
  16849.             if (!$backtrace) {
  16850.                 $backtrace = debug_backtrace();
  16851.             }
  16852.             $context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
  16853.         }
  16854.         
  16855.         // save error
  16856.         $time = explode(' ', microtime());
  16857.         $time = $time[1] + $time[0];
  16858.         $err = array(
  16859.                 'code' => $code,
  16860.                 'params' => $params,
  16861.                 'package' => $this->_package,
  16862.                 'level' => $level,
  16863.                 'time' => $time,
  16864.                 'context' => $context,
  16865.                 'message' => $msg,
  16866.                );
  16867.  
  16868.         if ($repackage) {
  16869.             $err['repackage'] = $repackage;
  16870.         }
  16871.  
  16872.         // set up the error message, if necessary
  16873.         if ($this->_msgCallback) {
  16874.             $msg = call_user_func_array($this->_msgCallback,
  16875.                                         array(&$this, $err));
  16876.             $err['message'] = $msg;
  16877.         }        
  16878.         $push = $log = true;
  16879.         $die = false;
  16880.         // try the overriding callback first
  16881.         $callback = $this->staticPopCallback();
  16882.         if ($callback) {
  16883.             $this->staticPushCallback($callback);
  16884.         }
  16885.         if (!is_callable($callback)) {
  16886.             // try the local callback next
  16887.             $callback = $this->popCallback();
  16888.             if (is_callable($callback)) {
  16889.                 $this->pushCallback($callback);
  16890.             } else {
  16891.                 // try the default callback
  16892.                 $callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
  16893.                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
  16894.                     $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
  16895.             }
  16896.         }
  16897.         if (is_callable($callback)) {
  16898.             switch(call_user_func($callback, $err)){
  16899.                 case PEAR_ERRORSTACK_IGNORE: 
  16900.                     return $err;
  16901.                 break;
  16902.                 case PEAR_ERRORSTACK_PUSH: 
  16903.                     $log = false;
  16904.                 break;
  16905.                 case PEAR_ERRORSTACK_LOG: 
  16906.                     $push = false;
  16907.                 break;
  16908.                 case PEAR_ERRORSTACK_DIE: 
  16909.                     $die = true;
  16910.                 break;
  16911.                 // anything else returned has the same effect as pushandlog
  16912.             }
  16913.         }
  16914.         if ($push) {
  16915.             array_unshift($this->_errors, $err);
  16916.             if (!isset($this->_errorsByLevel[$err['level']])) {
  16917.                 $this->_errorsByLevel[$err['level']] = array();
  16918.             }
  16919.             $this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
  16920.         }
  16921.         if ($log) {
  16922.             if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
  16923.                 $this->_log($err);
  16924.             }
  16925.         }
  16926.         if ($die) {
  16927.             die();
  16928.         }
  16929.         if ($this->_compat && $push) {
  16930.             return $this->raiseError($msg, $code, null, null, $err);
  16931.         }
  16932.         return $err;
  16933.     }
  16934.     
  16935.     /**
  16936.      * Static version of {@link push()}
  16937.      * 
  16938.      * @param string $package   Package name this error belongs to
  16939.      * @param int    $code      Package-specific error code
  16940.      * @param string $level     Error level.  This is NOT spell-checked
  16941.      * @param array  $params    associative array of error parameters
  16942.      * @param string $msg       Error message, or a portion of it if the message
  16943.      *                          is to be generated
  16944.      * @param array  $repackage If this error re-packages an error pushed by
  16945.      *                          another package, place the array returned from
  16946.      *                          {@link pop()} in this parameter
  16947.      * @param array  $backtrace Protected parameter: use this to pass in the
  16948.      *                          {@link debug_backtrace()} that should be used
  16949.      *                          to find error context
  16950.      * @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
  16951.      *                          thrown.  see docs for {@link push()}
  16952.      * @static
  16953.      */
  16954.     function staticPush($package, $code, $level = 'error', $params = array(),
  16955.                         $msg = false, $repackage = false, $backtrace = false)
  16956.     {
  16957.         $s = &PEAR_ErrorStack::singleton($package);
  16958.         if ($s->_contextCallback) {
  16959.             if (!$backtrace) {
  16960.                 if (function_exists('debug_backtrace')) {
  16961.                     $backtrace = debug_backtrace();
  16962.                 }
  16963.             }
  16964.         }
  16965.         return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
  16966.     }
  16967.     
  16968.     /**
  16969.      * Log an error using PEAR::Log
  16970.      * @param array $err Error array
  16971.      * @param array $levels Error level => Log constant map
  16972.      * @access protected
  16973.      */
  16974.     function _log($err)
  16975.     {
  16976.         if ($this->_logger) {
  16977.             $logger = &$this->_logger;
  16978.         } else {
  16979.             $logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
  16980.         }
  16981.         if (is_a($logger, 'Log')) {
  16982.             $levels = array(
  16983.                 'exception' => PEAR_LOG_CRIT,
  16984.                 'alert' => PEAR_LOG_ALERT,
  16985.                 'critical' => PEAR_LOG_CRIT,
  16986.                 'error' => PEAR_LOG_ERR,
  16987.                 'warning' => PEAR_LOG_WARNING,
  16988.                 'notice' => PEAR_LOG_NOTICE,
  16989.                 'info' => PEAR_LOG_INFO,
  16990.                 'debug' => PEAR_LOG_DEBUG);
  16991.             if (isset($levels[$err['level']])) {
  16992.                 $level = $levels[$err['level']];
  16993.             } else {
  16994.                 $level = PEAR_LOG_INFO;
  16995.             }
  16996.             $logger->log($err['message'], $level, $err);
  16997.         } else { // support non-standard logs
  16998.             call_user_func($logger, $err);
  16999.         }
  17000.     }
  17001.  
  17002.     
  17003.     /**
  17004.      * Pop an error off of the error stack
  17005.      * 
  17006.      * @return false|array
  17007.      * @since 0.4alpha it is no longer possible to specify a specific error
  17008.      * level to return - the last error pushed will be returned, instead
  17009.      */
  17010.     function pop()
  17011.     {
  17012.         $err = @array_shift($this->_errors);
  17013.         if (!is_null($err)) {
  17014.             @array_pop($this->_errorsByLevel[$err['level']]);
  17015.             if (!count($this->_errorsByLevel[$err['level']])) {
  17016.                 unset($this->_errorsByLevel[$err['level']]);
  17017.             }
  17018.         }
  17019.         return $err;
  17020.     }
  17021.  
  17022.     /**
  17023.      * Pop an error off of the error stack, static method
  17024.      *
  17025.      * @param string package name
  17026.      * @return boolean
  17027.      * @since PEAR1.5.0a1
  17028.      */
  17029.     function staticPop($package)
  17030.     {
  17031.         if ($package) {
  17032.             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  17033.                 return false;
  17034.             }
  17035.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
  17036.         }
  17037.     }
  17038.  
  17039.     /**
  17040.      * Determine whether there are any errors on the stack
  17041.      * @param string|array Level name.  Use to determine if any errors
  17042.      * of level (string), or levels (array) have been pushed
  17043.      * @return boolean
  17044.      */
  17045.     function hasErrors($level = false)
  17046.     {
  17047.         if ($level) {
  17048.             return isset($this->_errorsByLevel[$level]);
  17049.         }
  17050.         return count($this->_errors);
  17051.     }
  17052.     
  17053.     /**
  17054.      * Retrieve all errors since last purge
  17055.      * 
  17056.      * @param boolean set in order to empty the error stack
  17057.      * @param string level name, to return only errors of a particular severity
  17058.      * @return array
  17059.      */
  17060.     function getErrors($purge = false, $level = false)
  17061.     {
  17062.         if (!$purge) {
  17063.             if ($level) {
  17064.                 if (!isset($this->_errorsByLevel[$level])) {
  17065.                     return array();
  17066.                 } else {
  17067.                     return $this->_errorsByLevel[$level];
  17068.                 }
  17069.             } else {
  17070.                 return $this->_errors;
  17071.             }
  17072.         }
  17073.         if ($level) {
  17074.             $ret = $this->_errorsByLevel[$level];
  17075.             foreach ($this->_errorsByLevel[$level] as $i => $unused) {
  17076.                 // entries are references to the $_errors array
  17077.                 $this->_errorsByLevel[$level][$i] = false;
  17078.             }
  17079.             // array_filter removes all entries === false
  17080.             $this->_errors = array_filter($this->_errors);
  17081.             unset($this->_errorsByLevel[$level]);
  17082.             return $ret;
  17083.         }
  17084.         $ret = $this->_errors;
  17085.         $this->_errors = array();
  17086.         $this->_errorsByLevel = array();
  17087.         return $ret;
  17088.     }
  17089.     
  17090.     /**
  17091.      * Determine whether there are any errors on a single error stack, or on any error stack
  17092.      *
  17093.      * The optional parameter can be used to test the existence of any errors without the need of
  17094.      * singleton instantiation
  17095.      * @param string|false Package name to check for errors
  17096.      * @param string Level name to check for a particular severity
  17097.      * @return boolean
  17098.      * @static
  17099.      */
  17100.     function staticHasErrors($package = false, $level = false)
  17101.     {
  17102.         if ($package) {
  17103.             if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
  17104.                 return false;
  17105.             }
  17106.             return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
  17107.         }
  17108.         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  17109.             if ($obj->hasErrors($level)) {
  17110.                 return true;
  17111.             }
  17112.         }
  17113.         return false;
  17114.     }
  17115.     
  17116.     /**
  17117.      * Get a list of all errors since last purge, organized by package
  17118.      * @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
  17119.      * @param boolean $purge Set to purge the error stack of existing errors
  17120.      * @param string  $level Set to a level name in order to retrieve only errors of a particular level
  17121.      * @param boolean $merge Set to return a flat array, not organized by package
  17122.      * @param array   $sortfunc Function used to sort a merged array - default
  17123.      *        sorts by time, and should be good for most cases
  17124.      * @static
  17125.      * @return array 
  17126.      */
  17127.     function staticGetErrors($purge = false, $level = false, $merge = false,
  17128.                              $sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
  17129.     {
  17130.         $ret = array();
  17131.         if (!is_callable($sortfunc)) {
  17132.             $sortfunc = array('PEAR_ErrorStack', '_sortErrors');
  17133.         }
  17134.         foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
  17135.             $test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
  17136.             if ($test) {
  17137.                 if ($merge) {
  17138.                     $ret = array_merge($ret, $test);
  17139.                 } else {
  17140.                     $ret[$package] = $test;
  17141.                 }
  17142.             }
  17143.         }
  17144.         if ($merge) {
  17145.             usort($ret, $sortfunc);
  17146.         }
  17147.         return $ret;
  17148.     }
  17149.     
  17150.     /**
  17151.      * Error sorting function, sorts by time
  17152.      * @access private
  17153.      */
  17154.     function _sortErrors($a, $b)
  17155.     {
  17156.         if ($a['time'] == $b['time']) {
  17157.             return 0;
  17158.         }
  17159.         if ($a['time'] < $b['time']) {
  17160.             return 1;
  17161.         }
  17162.         return -1;
  17163.     }
  17164.  
  17165.     /**
  17166.      * Standard file/line number/function/class context callback
  17167.      *
  17168.      * This function uses a backtrace generated from {@link debug_backtrace()}
  17169.      * and so will not work at all in PHP < 4.3.0.  The frame should
  17170.      * reference the frame that contains the source of the error.
  17171.      * @return array|false either array('file' => file, 'line' => line,
  17172.      *         'function' => function name, 'class' => class name) or
  17173.      *         if this doesn't work, then false
  17174.      * @param unused
  17175.      * @param integer backtrace frame.
  17176.      * @param array Results of debug_backtrace()
  17177.      * @static
  17178.      */
  17179.     function getFileLine($code, $params, $backtrace = null)
  17180.     {
  17181.         if ($backtrace === null) {
  17182.             return false;
  17183.         }
  17184.         $frame = 0;
  17185.         $functionframe = 1;
  17186.         if (!isset($backtrace[1])) {
  17187.             $functionframe = 0;
  17188.         } else {
  17189.             while (isset($backtrace[$functionframe]['function']) &&
  17190.                   $backtrace[$functionframe]['function'] == 'eval' &&
  17191.                   isset($backtrace[$functionframe + 1])) {
  17192.                 $functionframe++;
  17193.             }
  17194.         }
  17195.         if (isset($backtrace[$frame])) {
  17196.             if (!isset($backtrace[$frame]['file'])) {
  17197.                 $frame++;
  17198.             }
  17199.             $funcbacktrace = $backtrace[$functionframe];
  17200.             $filebacktrace = $backtrace[$frame];
  17201.             $ret = array('file' => $filebacktrace['file'],
  17202.                          'line' => $filebacktrace['line']);
  17203.             // rearrange for eval'd code or create function errors
  17204.             if (strpos($filebacktrace['file'], '(') && 
  17205.                   preg_match(';^(.*?)\((\d+)\) : (.*?)$;', $filebacktrace['file'],
  17206.                   $matches)) {
  17207.                 $ret['file'] = $matches[1];
  17208.                 $ret['line'] = $matches[2] + 0;
  17209.             }
  17210.             if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
  17211.                 if ($funcbacktrace['function'] != 'eval') {
  17212.                     if ($funcbacktrace['function'] == '__lambda_func') {
  17213.                         $ret['function'] = 'create_function() code';
  17214.                     } else {
  17215.                         $ret['function'] = $funcbacktrace['function'];
  17216.                     }
  17217.                 }
  17218.             }
  17219.             if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
  17220.                 $ret['class'] = $funcbacktrace['class'];
  17221.             }
  17222.             return $ret;
  17223.         }
  17224.         return false;
  17225.     }
  17226.     
  17227.     /**
  17228.      * Standard error message generation callback
  17229.      * 
  17230.      * This method may also be called by a custom error message generator
  17231.      * to fill in template values from the params array, simply
  17232.      * set the third parameter to the error message template string to use
  17233.      * 
  17234.      * The special variable %__msg% is reserved: use it only to specify
  17235.      * where a message passed in by the user should be placed in the template,
  17236.      * like so:
  17237.      * 
  17238.      * Error message: %msg% - internal error
  17239.      * 
  17240.      * If the message passed like so:
  17241.      * 
  17242.      * <code>
  17243.      * $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
  17244.      * </code>
  17245.      * 
  17246.      * The returned error message will be "Error message: server error 500 -
  17247.      * internal error"
  17248.      * @param PEAR_ErrorStack
  17249.      * @param array
  17250.      * @param string|false Pre-generated error message template
  17251.      * @static
  17252.      * @return string
  17253.      */
  17254.     function getErrorMessage(&$stack, $err, $template = false)
  17255.     {
  17256.         if ($template) {
  17257.             $mainmsg = $template;
  17258.         } else {
  17259.             $mainmsg = $stack->getErrorMessageTemplate($err['code']);
  17260.         }
  17261.         $mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
  17262.         if (is_array($err['params']) && count($err['params'])) {
  17263.             foreach ($err['params'] as $name => $val) {
  17264.                 if (is_array($val)) {
  17265.                     // @ is needed in case $val is a multi-dimensional array
  17266.                     $val = @implode(', ', $val);
  17267.                 }
  17268.                 if (is_object($val)) {
  17269.                     if (method_exists($val, '__toString')) {
  17270.                         $val = $val->__toString();
  17271.                     } else {
  17272.                         PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
  17273.                             'warning', array('obj' => get_class($val)),
  17274.                             'object %obj% passed into getErrorMessage, but has no __toString() method');
  17275.                         $val = 'Object';
  17276.                     }
  17277.                 }
  17278.                 $mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
  17279.             }
  17280.         }
  17281.         return $mainmsg;
  17282.     }
  17283.     
  17284.     /**
  17285.      * Standard Error Message Template generator from code
  17286.      * @return string
  17287.      */
  17288.     function getErrorMessageTemplate($code)
  17289.     {
  17290.         if (!isset($this->_errorMsgs[$code])) {
  17291.             return '%__msg%';
  17292.         }
  17293.         return $this->_errorMsgs[$code];
  17294.     }
  17295.     
  17296.     /**
  17297.      * Set the Error Message Template array
  17298.      * 
  17299.      * The array format must be:
  17300.      * <pre>
  17301.      * array(error code => 'message template',...)
  17302.      * </pre>
  17303.      * 
  17304.      * Error message parameters passed into {@link push()} will be used as input
  17305.      * for the error message.  If the template is 'message %foo% was %bar%', and the
  17306.      * parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
  17307.      * be 'message one was six'
  17308.      * @return string
  17309.      */
  17310.     function setErrorMessageTemplate($template)
  17311.     {
  17312.         $this->_errorMsgs = $template;
  17313.     }
  17314.     
  17315.     
  17316.     /**
  17317.      * emulate PEAR::raiseError()
  17318.      * 
  17319.      * @return PEAR_Error
  17320.      */
  17321.     function raiseError()
  17322.     {
  17323.         require_once 'phar://go-pear.phar/PEAR.php';
  17324.         $args = func_get_args();
  17325.         return call_user_func_array(array('PEAR', 'raiseError'), $args);
  17326.     }
  17327. }
  17328. $stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
  17329. $stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
  17330. ?>
  17331. <?php
  17332. /**
  17333.  * PEAR_Frontend, the singleton-based frontend for user input/output
  17334.  *
  17335.  * PHP versions 4 and 5
  17336.  *
  17337.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  17338.  * that is available through the world-wide-web at the following URI:
  17339.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  17340.  * the PHP License and are unable to obtain it through the web, please
  17341.  * send a note to license@php.net so we can mail you a copy immediately.
  17342.  *
  17343.  * @category   pear
  17344.  * @package    PEAR
  17345.  * @author     Greg Beaver <cellog@php.net>
  17346.  * @copyright  1997-2006 The PHP Group
  17347.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  17348.  * @version    CVS: $Id: Frontend.php,v 1.9 2006/03/03 13:13:07 pajoye Exp $
  17349.  * @link       http://pear.php.net/package/PEAR
  17350.  * @since      File available since Release 1.4.0a1
  17351.  */
  17352.  
  17353. /**
  17354.  * Which user interface class is being used.
  17355.  * @var string class name
  17356.  */
  17357. $GLOBALS['_PEAR_FRONTEND_CLASS'] = 'PEAR_Frontend_CLI';
  17358.  
  17359. /**
  17360.  * Instance of $_PEAR_Command_uiclass.
  17361.  * @var object
  17362.  */
  17363. $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = null;
  17364.  
  17365. /**
  17366.  * Singleton-based frontend for PEAR user input/output
  17367.  *
  17368.  * Note that frontend classes must implement userConfirm(), and shoul implement
  17369.  * displayFatalError() and outputData()
  17370.  * @category   pear
  17371.  * @package    PEAR
  17372.  * @author     Greg Beaver <cellog@php.net>
  17373.  * @copyright  1997-2006 The PHP Group
  17374.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  17375.  * @version    Release: @package_version@
  17376.  * @link       http://pear.php.net/package/PEAR
  17377.  * @since      Class available since Release 1.4.0a1
  17378.  */
  17379. class PEAR_Frontend extends PEAR
  17380. {
  17381.     /**
  17382.      * Retrieve the frontend object
  17383.      * @return PEAR_Frontend_CLI|PEAR_Frontend_Web|PEAR_Frontend_Gtk
  17384.      * @static
  17385.      */
  17386.     function &singleton($type = null)
  17387.     {
  17388.         if ($type === null) {
  17389.             if (!isset($GLOBALS['_PEAR_FRONTEND_SINGLETON'])) {
  17390.                 $a = false;
  17391.                 return $a;
  17392.             }
  17393.             return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  17394.         } else {
  17395.             $a = PEAR_Frontend::setFrontendClass($type);
  17396.             return $a;
  17397.         }
  17398.     }
  17399.  
  17400.     /**
  17401.      * Set the frontend class that will be used by calls to {@link singleton()}
  17402.      *
  17403.      * Frontends are expected to conform to the PEAR naming standard of
  17404.      * _ => DIRECTORY_SEPARATOR (PEAR_Frontend_CLI is in PEAR/Frontend/CLI.php)
  17405.      * @param string $uiclass full class name
  17406.      * @return PEAR_Frontend
  17407.      * @static
  17408.      */
  17409.     function &setFrontendClass($uiclass)
  17410.     {
  17411.         if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
  17412.               is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], $uiclass)) {
  17413.             return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  17414.         }
  17415.         if (!class_exists($uiclass)) {
  17416.             $file = str_replace('_', '/', $uiclass) . '.php';
  17417.             if (true) {
  17418.                 include_once 'phar://go-pear.phar/' . $file;
  17419.             }
  17420.         }
  17421.         if (class_exists($uiclass)) {
  17422.             $obj = &new $uiclass;
  17423.             // quick test to see if this class implements a few of the most
  17424.             // important frontend methods
  17425.             if (method_exists($obj, 'userConfirm')) {
  17426.                 $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$obj;
  17427.                 $GLOBALS['_PEAR_FRONTEND_CLASS'] = $uiclass;
  17428.                 return $obj;
  17429.             } else {
  17430.                 $err = PEAR::raiseError("not a frontend class: $uiclass");
  17431.                 return $err;
  17432.             }
  17433.         }
  17434.         $err = PEAR::raiseError("no such class: $uiclass");
  17435.         return $err;
  17436.     }
  17437.  
  17438.     /**
  17439.      * Set the frontend class that will be used by calls to {@link singleton()}
  17440.      *
  17441.      * Frontends are expected to be a descendant of PEAR_Frontend
  17442.      * @param PEAR_Frontend
  17443.      * @return PEAR_Frontend
  17444.      * @static
  17445.      */
  17446.     function &setFrontendObject($uiobject)
  17447.     {
  17448.         if (is_object($GLOBALS['_PEAR_FRONTEND_SINGLETON']) &&
  17449.               is_a($GLOBALS['_PEAR_FRONTEND_SINGLETON'], get_class($uiobject))) {
  17450.             return $GLOBALS['_PEAR_FRONTEND_SINGLETON'];
  17451.         }
  17452.         if (!is_a($uiobject, 'PEAR_Frontend')) {
  17453.             $err = PEAR::raiseError('not a valid frontend class: (' .
  17454.                 get_class($uiobject) . ')');
  17455.             return $err;
  17456.         }
  17457.         // quick test to see if this class implements a few of the most
  17458.         // important frontend methods
  17459.         if (method_exists($uiobject, 'userConfirm')) {
  17460.             $GLOBALS['_PEAR_FRONTEND_SINGLETON'] = &$uiobject;
  17461.             $GLOBALS['_PEAR_FRONTEND_CLASS'] = get_class($uiobject);
  17462.             return $uiobject;
  17463.         } else {
  17464.             $err = PEAR::raiseError("not a value frontend class: (" . get_class($uiobject)
  17465.                 . ')');
  17466.             return $err;
  17467.         }
  17468.     }
  17469.  
  17470.     /**
  17471.      * @param string $path relative or absolute include path
  17472.      * @return boolean
  17473.      * @static
  17474.      */
  17475.     function isIncludeable($path)
  17476.     {
  17477.         if (file_exists($path) && is_readable($path)) {
  17478.             return true;
  17479.         }
  17480.         $ipath = explode(PATH_SEPARATOR, ini_get('include_path'));
  17481.         foreach ($ipath as $include) {
  17482.             $test = realpath($include . DIRECTORY_SEPARATOR . $path);
  17483.             if (!$test) { // support wrappers like phar (realpath just don't work with them)
  17484.                 $test = $include . DIRECTORY_SEPARATOR . $path;
  17485.             }
  17486.             if (file_exists($test) && is_readable($test)) {
  17487.                 return true;
  17488.             }
  17489.         }
  17490.         return false;
  17491.     }
  17492.  
  17493.     /**
  17494.      * @param PEAR_Config
  17495.      */
  17496.     function setConfig(&$config)
  17497.     {
  17498.     }
  17499.  
  17500.     /**
  17501.      * This can be overridden to allow session-based temporary file management
  17502.      *
  17503.      * By default, all files are deleted at the end of a session.  The web installer
  17504.      * needs to be able to sustain a list over many sessions in order to support
  17505.      * user interaction with install scripts
  17506.      */
  17507.     function addTempFile($file)
  17508.     {
  17509.         $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
  17510.     }
  17511.  
  17512.     function log($msg, $append_crlf = true)
  17513.     {
  17514.     }
  17515. }
  17516. ?><?php
  17517. /**
  17518.  * PEAR_Frontend_CLI
  17519.  *
  17520.  * PHP versions 4 and 5
  17521.  *
  17522.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  17523.  * that is available through the world-wide-web at the following URI:
  17524.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  17525.  * the PHP License and are unable to obtain it through the web, please
  17526.  * send a note to license@php.net so we can mail you a copy immediately.
  17527.  *
  17528.  * @category   pear
  17529.  * @package    PEAR
  17530.  * @author     Stig Bakken <ssb@php.net>
  17531.  * @author     Greg Beaver <cellog@php.net>
  17532.  * @copyright  1997-2006 The PHP Group
  17533.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  17534.  * @version    CVS: $Id: CLI.php,v 1.65 2006/10/01 22:29:13 cellog Exp $
  17535.  * @link       http://pear.php.net/package/PEAR
  17536.  * @since      File available since Release 0.1
  17537.  */
  17538. /**
  17539.  * base class
  17540.  */
  17541. require_once 'phar://go-pear.phar/PEAR/Frontend.php';
  17542.  
  17543. /**
  17544.  * Command-line Frontend for the PEAR Installer
  17545.  * @category   pear
  17546.  * @package    PEAR
  17547.  * @author     Stig Bakken <ssb@php.net>
  17548.  * @author     Greg Beaver <cellog@php.net>
  17549.  * @copyright  1997-2006 The PHP Group
  17550.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  17551.  * @version    Release: @package_version@
  17552.  * @link       http://pear.php.net/package/PEAR
  17553.  * @since      Class available since Release 0.1
  17554.  */
  17555. class PEAR_Frontend_CLI extends PEAR_Frontend
  17556. {
  17557.     // {{{ properties
  17558.  
  17559.     /**
  17560.      * What type of user interface this frontend is for.
  17561.      * @var string
  17562.      * @access public
  17563.      */
  17564.     var $type = 'CLI';
  17565.     var $lp = ''; // line prefix
  17566.  
  17567.     var $params = array();
  17568.     var $term = array(
  17569.         'bold' => '',
  17570.         'normal' => '',
  17571.         );
  17572.  
  17573.     // }}}
  17574.  
  17575.     // {{{ constructor
  17576.  
  17577.     function PEAR_Frontend_CLI()
  17578.     {
  17579.         parent::PEAR();
  17580.         $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1
  17581.         if (function_exists('posix_isatty') && !posix_isatty(1)) {
  17582.             // output is being redirected to a file or through a pipe
  17583.         } elseif ($term) {
  17584.             // XXX can use ncurses extension here, if available
  17585.             if (preg_match('/^(xterm|vt220|linux)/', $term)) {
  17586.                 $this->term['bold'] = sprintf("%c%c%c%c", 27, 91, 49, 109);
  17587.                 $this->term['normal']=sprintf("%c%c%c", 27, 91, 109);
  17588.             } elseif (preg_match('/^vt100/', $term)) {
  17589.                 $this->term['bold'] = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0);
  17590.                 $this->term['normal']=sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0);
  17591.             }
  17592.         } elseif (OS_WINDOWS) {
  17593.             // XXX add ANSI codes here
  17594.         }
  17595.     }
  17596.  
  17597.     // }}}
  17598.  
  17599.     // {{{ displayLine(text)
  17600.  
  17601.     function displayLine($text)
  17602.     {
  17603.         trigger_error("PEAR_Frontend_CLI::displayLine deprecated", E_USER_ERROR);
  17604.     }
  17605.  
  17606.     function _displayLine($text)
  17607.     {
  17608.         print "$this->lp$text\n";
  17609.     }
  17610.  
  17611.     // }}}
  17612.     // {{{ display(text)
  17613.  
  17614.     function display($text)
  17615.     {
  17616.         trigger_error("PEAR_Frontend_CLI::display deprecated", E_USER_ERROR);
  17617.     }
  17618.  
  17619.     function _display($text)
  17620.     {
  17621.         print $text;
  17622.     }
  17623.  
  17624.     // }}}
  17625.     // {{{ displayError(eobj)
  17626.  
  17627.     /**
  17628.      * @param object PEAR_Error object
  17629.      */
  17630.     function displayError($eobj)
  17631.     {
  17632.         return $this->_displayLine($eobj->getMessage());
  17633.     }
  17634.  
  17635.     // }}}
  17636.     // {{{ displayFatalError(eobj)
  17637.  
  17638.     /**
  17639.      * @param object PEAR_Error object
  17640.      */
  17641.     function displayFatalError($eobj)
  17642.     {
  17643.         $this->displayError($eobj);
  17644.         if (class_exists('PEAR_Config')) {
  17645.             $config = &PEAR_Config::singleton();
  17646.             if ($config->get('verbose') > 5) {
  17647.                 if (function_exists('debug_print_backtrace')) {
  17648.                     debug_print_backtrace();
  17649.                 } elseif (function_exists('debug_backtrace')) {
  17650.                     $trace = debug_backtrace();
  17651.                     $raised = false;
  17652.                     foreach ($trace as $i => $frame) {
  17653.                         if (!$raised) {
  17654.                             if (isset($frame['class']) && strtolower($frame['class']) ==
  17655.                                   'pear' && strtolower($frame['function']) == 'raiseerror') {
  17656.                                 $raised = true;
  17657.                             } else {
  17658.                                 continue;
  17659.                             }
  17660.                         }
  17661.                         if (!isset($frame['class'])) {
  17662.                             $frame['class'] = '';
  17663.                         }
  17664.                         if (!isset($frame['type'])) {
  17665.                             $frame['type'] = '';
  17666.                         }
  17667.                         if (!isset($frame['function'])) {
  17668.                             $frame['function'] = '';
  17669.                         }
  17670.                         if (!isset($frame['line'])) {
  17671.                             $frame['line'] = '';
  17672.                         }
  17673.                         $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]");
  17674.                     }
  17675.                 }
  17676.             }
  17677.         }
  17678.         exit(1);
  17679.     }
  17680.  
  17681.     // }}}
  17682.     // {{{ displayHeading(title)
  17683.  
  17684.     function displayHeading($title)
  17685.     {
  17686.         trigger_error("PEAR_Frontend_CLI::displayHeading deprecated", E_USER_ERROR);
  17687.     }
  17688.  
  17689.     function _displayHeading($title)
  17690.     {
  17691.         print $this->lp.$this->bold($title)."\n";
  17692.         print $this->lp.str_repeat("=", strlen($title))."\n";
  17693.     }
  17694.  
  17695.     // }}}
  17696.  
  17697.     /**
  17698.      * Instruct the runInstallScript method to skip a paramgroup that matches the
  17699.      * id value passed in.
  17700.      *
  17701.      * This method is useful for dynamically configuring which sections of a post-install script
  17702.      * will be run based on the user's setup, which is very useful for making flexible
  17703.      * post-install scripts without losing the cross-Frontend ability to retrieve user input
  17704.      * @param string
  17705.      */
  17706.     function skipParamgroup($id)
  17707.     {
  17708.         $this->_skipSections[$id] = true;
  17709.     }
  17710.  
  17711.     function runPostinstallScripts(&$scripts)
  17712.     {
  17713.         foreach ($scripts as $i => $script) {
  17714.             $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj);
  17715.         }
  17716.     }
  17717.  
  17718.     /**
  17719.      * @param array $xml contents of postinstallscript tag
  17720.      * @param object $script post-installation script
  17721.      * @param string install|upgrade
  17722.      */
  17723.     function runInstallScript($xml, &$script)
  17724.     {
  17725.         $this->_skipSections = array();
  17726.         if (!is_array($xml) || !isset($xml['paramgroup'])) {
  17727.             $script->run(array(), '_default');
  17728.         } else {
  17729.             $completedPhases = array();
  17730.             if (!isset($xml['paramgroup'][0])) {
  17731.                 $xml['paramgroup'] = array($xml['paramgroup']);
  17732.             }
  17733.             foreach ($xml['paramgroup'] as $group) {
  17734.                 if (isset($this->_skipSections[$group['id']])) {
  17735.                     // the post-install script chose to skip this section dynamically
  17736.                     continue;
  17737.                 }
  17738.                 if (isset($group['name'])) {
  17739.                     $paramname = explode('::', $group['name']);
  17740.                     if ($lastgroup['id'] != $paramname[0]) {
  17741.                         continue;
  17742.                     }
  17743.                     $group['name'] = $paramname[1];
  17744.                     if (isset($answers)) {
  17745.                         if (isset($answers[$group['name']])) {
  17746.                             switch ($group['conditiontype']) {
  17747.                                 case '=' :
  17748.                                     if ($answers[$group['name']] != $group['value']) {
  17749.                                         continue 2;
  17750.                                     }
  17751.                                 break;
  17752.                                 case '!=' :
  17753.                                     if ($answers[$group['name']] == $group['value']) {
  17754.                                         continue 2;
  17755.                                     }
  17756.                                 break;
  17757.                                 case 'preg_match' :
  17758.                                     if (!@preg_match('/' . $group['value'] . '/',
  17759.                                           $answers[$group['name']])) {
  17760.                                         continue 2;
  17761.                                     }
  17762.                                 break;
  17763.                                 default :
  17764.                                 return;
  17765.                             }
  17766.                         }
  17767.                     } else {
  17768.                         return;
  17769.                     }
  17770.                 }
  17771.                 $lastgroup = $group;
  17772.                 if (isset($group['instructions'])) {
  17773.                     $this->_display($group['instructions']);
  17774.                 }
  17775.                 if (!isset($group['param'][0])) {
  17776.                     $group['param'] = array($group['param']);
  17777.                 }
  17778.                 if (isset($group['param'])) {
  17779.                     if (method_exists($script, 'postProcessPrompts')) {
  17780.                         $prompts = $script->postProcessPrompts($group['param'], $group['id']);
  17781.                         if (!is_array($prompts) || count($prompts) != count($group['param'])) {
  17782.                             $this->outputData('postinstall', 'Error: post-install script did not ' .
  17783.                                 'return proper post-processed prompts');
  17784.                             $prompts = $group['param'];
  17785.                         } else {
  17786.                             foreach ($prompts as $i => $var) {
  17787.                                 if (!is_array($var) || !isset($var['prompt']) ||
  17788.                                       !isset($var['name']) ||
  17789.                                       ($var['name'] != $group['param'][$i]['name']) ||
  17790.                                       ($var['type'] != $group['param'][$i]['type'])) {
  17791.                                     $this->outputData('postinstall', 'Error: post-install script ' .
  17792.                                         'modified the variables or prompts, severe security risk. ' .
  17793.                                         'Will instead use the defaults from the package.xml');
  17794.                                     $prompts = $group['param'];
  17795.                                 }
  17796.                             }
  17797.                         }
  17798.                         $answers = $this->confirmDialog($prompts);
  17799.                     } else {
  17800.                         $answers = $this->confirmDialog($group['param']);
  17801.                     }
  17802.                 }
  17803.                 if ((isset($answers) && $answers) || !isset($group['param'])) {
  17804.                     if (!isset($answers)) {
  17805.                         $answers = array();
  17806.                     }
  17807.                     array_unshift($completedPhases, $group['id']);
  17808.                     if (!$script->run($answers, $group['id'])) {
  17809.                         $script->run($completedPhases, '_undoOnError');
  17810.                         return;
  17811.                     }
  17812.                 } else {
  17813.                     $script->run($completedPhases, '_undoOnError');
  17814.                     return;
  17815.                 }
  17816.             }
  17817.         }
  17818.     }
  17819.  
  17820.     /**
  17821.      * Ask for user input, confirm the answers and continue until the user is satisfied
  17822.      * @param array an array of arrays, format array('name' => 'paramname', 'prompt' =>
  17823.      *              'text to display', 'type' => 'string'[, default => 'default value'])
  17824.      * @return array
  17825.      */
  17826.     function confirmDialog($params)
  17827.     {
  17828.         $answers = array();
  17829.         $prompts = $types = array();
  17830.         foreach ($params as $param) {
  17831.             $prompts[$param['name']] = $param['prompt'];
  17832.             $types[$param['name']] = $param['type'];
  17833.             if (isset($param['default'])) {
  17834.                 $answers[$param['name']] = $param['default'];
  17835.             } else {
  17836.                 $answers[$param['name']] = '';
  17837.             }
  17838.         }
  17839.         $tried = false;
  17840.         do {
  17841.             if ($tried) {
  17842.                 $i = 1;
  17843.                 foreach ($answers as $var => $value) {
  17844.                     if (!strlen($value)) {
  17845.                         echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n");
  17846.                     }
  17847.                     $i++;
  17848.                 }
  17849.             }
  17850.             $answers = $this->userDialog('', $prompts, $types, $answers);
  17851.             $tried = true;
  17852.         } while (is_array($answers) && count(array_filter($answers)) != count($prompts));
  17853.         return $answers;
  17854.     }
  17855.     // {{{ userDialog(prompt, [type], [default])
  17856.  
  17857.     function userDialog($command, $prompts, $types = array(), $defaults = array(),
  17858.                         $screensize = 20)
  17859.     {
  17860.         if (!is_array($prompts)) {
  17861.             return array();
  17862.         }
  17863.         $testprompts = array_keys($prompts);
  17864.         $result = $defaults;
  17865.         if (!defined('STDIN')) {
  17866.             $fp = fopen('php://stdin', 'r');
  17867.         } else {
  17868.             $fp = STDIN;
  17869.         }
  17870.         reset($prompts);
  17871.         if (count($prompts) == 1 && $types[key($prompts)] == 'yesno') {
  17872.             foreach ($prompts as $key => $prompt) {
  17873.                 $type = $types[$key];
  17874.                 $default = @$defaults[$key];
  17875.                 print "$prompt ";
  17876.                 if ($default) {
  17877.                     print "[$default] ";
  17878.                 }
  17879.                 print ": ";
  17880.                 if (version_compare(phpversion(), '5.0.0', '<')) {
  17881.                     $line = fgets($fp, 2048);
  17882.                 } else {
  17883.                     if (!defined('STDIN')) {
  17884.                         define('STDIN', fopen('php://stdin', 'r'));
  17885.                     }
  17886.                     $line = fgets(STDIN, 2048);
  17887.                 }
  17888.                 if ($default && trim($line) == "") {
  17889.                     $result[$key] = $default;
  17890.                 } else {
  17891.                     $result[$key] = trim($line);
  17892.                 }
  17893.             }
  17894.             return $result;
  17895.         }
  17896.         while (true) {
  17897.             $descLength = max(array_map('strlen', $prompts));
  17898.             $descFormat = "%-{$descLength}s";
  17899.             $last = count($prompts);
  17900.  
  17901.             $i = 0;
  17902.             foreach ($prompts as $n => $var) {
  17903.                 printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], isset($result[$n]) ?
  17904.                     $result[$n] : null);
  17905.             }
  17906.  
  17907.             print "\n1-$last, 'all', 'abort', or Enter to continue: ";
  17908.             $tmp = trim(fgets($fp, 1024));
  17909.             if (empty($tmp)) {
  17910.                 break;
  17911.             }
  17912.             if ($tmp == 'abort') {
  17913.                 return false;
  17914.             }
  17915.             if (isset($testprompts[(int)$tmp - 1])) {
  17916.                 $var = $testprompts[(int)$tmp - 1];
  17917.                 $desc = $prompts[$var];
  17918.                 $current = $result[$var];
  17919.                 print "$desc [$current] : ";
  17920.                 $tmp = trim(fgets($fp, 1024));
  17921.                 if (trim($tmp) !== '') {
  17922.                     $result[$var] = trim($tmp);
  17923.                 }
  17924.             } elseif ($tmp == 'all') {
  17925.                 foreach ($prompts as $var => $desc) {
  17926.                     $current = $result[$var];
  17927.                     print "$desc [$current] : ";
  17928.                     $tmp = trim(fgets($fp, 1024));
  17929.                     if (trim($tmp) !== '') {
  17930.                         $result[$var] = trim($tmp);
  17931.                     }
  17932.                 }
  17933.             }
  17934.         }
  17935.         if (!defined('STDIN')) {
  17936.             fclose($fp);
  17937.         }
  17938.         return $result;
  17939.     }
  17940.  
  17941.     // }}}
  17942.     // {{{ userConfirm(prompt, [default])
  17943.  
  17944.     function userConfirm($prompt, $default = 'yes')
  17945.     {
  17946.         trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR);
  17947.         static $positives = array('y', 'yes', 'on', '1');
  17948.         static $negatives = array('n', 'no', 'off', '0');
  17949.         print "$this->lp$prompt [$default] : ";
  17950.         $fp = fopen("php://stdin", "r");
  17951.         $line = fgets($fp, 2048);
  17952.         fclose($fp);
  17953.         $answer = strtolower(trim($line));
  17954.         if (empty($answer)) {
  17955.             $answer = $default;
  17956.         }
  17957.         if (in_array($answer, $positives)) {
  17958.             return true;
  17959.         }
  17960.         if (in_array($answer, $negatives)) {
  17961.             return false;
  17962.         }
  17963.         if (in_array($default, $positives)) {
  17964.             return true;
  17965.         }
  17966.         return false;
  17967.     }
  17968.  
  17969.     // }}}
  17970.     // {{{ startTable([params])
  17971.  
  17972.     function startTable($params = array())
  17973.     {
  17974.         trigger_error("PEAR_Frontend_CLI::startTable deprecated", E_USER_ERROR);
  17975.     }
  17976.  
  17977.     function _startTable($params = array())
  17978.     {
  17979.         $params['table_data'] = array();
  17980.         $params['widest'] = array();  // indexed by column
  17981.         $params['highest'] = array(); // indexed by row
  17982.         $params['ncols'] = 0;
  17983.         $this->params = $params;
  17984.     }
  17985.  
  17986.     // }}}
  17987.     // {{{ tableRow(columns, [rowparams], [colparams])
  17988.  
  17989.     function tableRow($columns, $rowparams = array(), $colparams = array())
  17990.     {
  17991.         trigger_error("PEAR_Frontend_CLI::tableRow deprecated", E_USER_ERROR);
  17992.     }
  17993.  
  17994.     function _tableRow($columns, $rowparams = array(), $colparams = array())
  17995.     {
  17996.         $highest = 1;
  17997.         for ($i = 0; $i < sizeof($columns); $i++) {
  17998.             $col = &$columns[$i];
  17999.             if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) {
  18000.                 $col = wordwrap($col, $colparams[$i]['wrap'], "\n", 0);
  18001.             }
  18002.             if (strpos($col, "\n") !== false) {
  18003.                 $multiline = explode("\n", $col);
  18004.                 $w = 0;
  18005.                 foreach ($multiline as $n => $line) {
  18006.                     if (strlen($line) > $w) {
  18007.                         $w = strlen($line);
  18008.                     }
  18009.                 }
  18010.                 $lines = sizeof($multiline);
  18011.             } else {
  18012.                 $w = strlen($col);
  18013.             }
  18014.  
  18015.             if (isset($this->params['widest'][$i])) {
  18016.                 if ($w > $this->params['widest'][$i]) {
  18017.                     $this->params['widest'][$i] = $w;
  18018.                 }
  18019.             } else {
  18020.                 $this->params['widest'][$i] = $w;
  18021.             }
  18022.             $tmp = count_chars($columns[$i], 1);
  18023.             // handle unix, mac and windows formats
  18024.             $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1;
  18025.             if ($lines > $highest) {
  18026.                 $highest = $lines;
  18027.             }
  18028.         }
  18029.         if (sizeof($columns) > $this->params['ncols']) {
  18030.             $this->params['ncols'] = sizeof($columns);
  18031.         }
  18032.         $new_row = array(
  18033.             'data' => $columns,
  18034.             'height' => $highest,
  18035.             'rowparams' => $rowparams,
  18036.             'colparams' => $colparams,
  18037.             );
  18038.         $this->params['table_data'][] = $new_row;
  18039.     }
  18040.  
  18041.     // }}}
  18042.     // {{{ endTable()
  18043.  
  18044.     function endTable()
  18045.     {
  18046.         trigger_error("PEAR_Frontend_CLI::endTable deprecated", E_USER_ERROR);
  18047.     }
  18048.  
  18049.     function _endTable()
  18050.     {
  18051.         extract($this->params);
  18052.         if (!empty($caption)) {
  18053.             $this->_displayHeading($caption);
  18054.         }
  18055.         if (count($table_data) == 0) {
  18056.             return;
  18057.         }
  18058.         if (!isset($width)) {
  18059.             $width = $widest;
  18060.         } else {
  18061.             for ($i = 0; $i < $ncols; $i++) {
  18062.                 if (!isset($width[$i])) {
  18063.                     $width[$i] = $widest[$i];
  18064.                 }
  18065.             }
  18066.         }
  18067.         $border = false;
  18068.         if (empty($border)) {
  18069.             $cellstart = '';
  18070.             $cellend = ' ';
  18071.             $rowend = '';
  18072.             $padrowend = false;
  18073.             $borderline = '';
  18074.         } else {
  18075.             $cellstart = '| ';
  18076.             $cellend = ' ';
  18077.             $rowend = '|';
  18078.             $padrowend = true;
  18079.             $borderline = '+';
  18080.             foreach ($width as $w) {
  18081.                 $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1);
  18082.                 $borderline .= '+';
  18083.             }
  18084.         }
  18085.         if ($borderline) {
  18086.             $this->_displayLine($borderline);
  18087.         }
  18088.         for ($i = 0; $i < sizeof($table_data); $i++) {
  18089.             extract($table_data[$i]);
  18090.             if (!is_array($rowparams)) {
  18091.                 $rowparams = array();
  18092.             }
  18093.             if (!is_array($colparams)) {
  18094.                 $colparams = array();
  18095.             }
  18096.             $rowlines = array();
  18097.             if ($height > 1) {
  18098.                 for ($c = 0; $c < sizeof($data); $c++) {
  18099.                     $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]);
  18100.                     if (sizeof($rowlines[$c]) < $height) {
  18101.                         $rowlines[$c] = array_pad($rowlines[$c], $height, '');
  18102.                     }
  18103.                 }
  18104.             } else {
  18105.                 for ($c = 0; $c < sizeof($data); $c++) {
  18106.                     $rowlines[$c] = array($data[$c]);
  18107.                 }
  18108.             }
  18109.             for ($r = 0; $r < $height; $r++) {
  18110.                 $rowtext = '';
  18111.                 for ($c = 0; $c < sizeof($data); $c++) {
  18112.                     if (isset($colparams[$c])) {
  18113.                         $attribs = array_merge($rowparams, $colparams);
  18114.                     } else {
  18115.                         $attribs = $rowparams;
  18116.                     }
  18117.                     $w = isset($width[$c]) ? $width[$c] : 0;
  18118.                     //$cell = $data[$c];
  18119.                     $cell = $rowlines[$c][$r];
  18120.                     $l = strlen($cell);
  18121.                     if ($l > $w) {
  18122.                         $cell = substr($cell, 0, $w);
  18123.                     }
  18124.                     if (isset($attribs['bold'])) {
  18125.                         $cell = $this->bold($cell);
  18126.                     }
  18127.                     if ($l < $w) {
  18128.                         // not using str_pad here because we may
  18129.                         // add bold escape characters to $cell
  18130.                         $cell .= str_repeat(' ', $w - $l);
  18131.                     }
  18132.  
  18133.                     $rowtext .= $cellstart . $cell . $cellend;
  18134.                 }
  18135.                 if (!$border) {
  18136.                     $rowtext = rtrim($rowtext);
  18137.                 }
  18138.                 $rowtext .= $rowend;
  18139.                 $this->_displayLine($rowtext);
  18140.             }
  18141.         }
  18142.         if ($borderline) {
  18143.             $this->_displayLine($borderline);
  18144.         }
  18145.     }
  18146.  
  18147.     // }}}
  18148.     // {{{ outputData()
  18149.  
  18150.     function outputData($data, $command = '_default')
  18151.     {
  18152.         switch ($command) {
  18153.             case 'channel-info':
  18154.                 foreach ($data as $type => $section) {
  18155.                     if ($type == 'main') {
  18156.                         $section['data'] = array_values($section['data']);
  18157.                     }
  18158.                     $this->outputData($section);
  18159.                 }
  18160.                 break;
  18161.             case 'install':
  18162.             case 'upgrade':
  18163.             case 'upgrade-all':
  18164.                 if (isset($data['release_warnings'])) {
  18165.                     $this->_displayLine('');
  18166.                     $this->_startTable(array(
  18167.                         'border' => false,
  18168.                         'caption' => 'Release Warnings'
  18169.                         ));
  18170.                     $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55)));
  18171.                     $this->_endTable();
  18172.                     $this->_displayLine('');
  18173.                 }
  18174.                 $this->_displayLine($data['data']);
  18175.                 break;
  18176.             case 'search':
  18177.                 $this->_startTable($data);
  18178.                 if (isset($data['headline']) && is_array($data['headline'])) {
  18179.                     $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
  18180.                 }
  18181.  
  18182.                 foreach($data['data'] as $category) {
  18183.                     foreach($category as $pkg) {
  18184.                         $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
  18185.                     }
  18186.                 };
  18187.                 $this->_endTable();
  18188.                 break;
  18189.             case 'list-all':
  18190.                 $this->_startTable($data);
  18191.                 if (isset($data['headline']) && is_array($data['headline'])) {
  18192.                     $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
  18193.                 }
  18194.  
  18195.                 foreach($data['data'] as $category) {
  18196.                     foreach($category as $pkg) {
  18197.                         unset($pkg[4]);
  18198.                         unset($pkg[5]);
  18199.                         $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
  18200.                     }
  18201.                 };
  18202.                 $this->_endTable();
  18203.                 break;
  18204.             case 'config-show':
  18205.                 $data['border'] = false;
  18206.                 $opts = array(0 => array('wrap' => 30),
  18207.                               1 => array('wrap' => 20),
  18208.                               2 => array('wrap' => 35));
  18209.                 $this->_startTable($data);
  18210.                 if (isset($data['headline']) && is_array($data['headline'])) {
  18211.                     $this->_tableRow($data['headline'],
  18212.                                      array('bold' => true),
  18213.                                      $opts);
  18214.                 }
  18215.                 foreach($data['data'] as $group) {
  18216.                     foreach($group as $value) {
  18217.                         if ($value[2] == '') {
  18218.                             $value[2] = "<not set>";
  18219.                         }
  18220.                         $this->_tableRow($value, null, $opts);
  18221.                     }
  18222.                 }
  18223.                 $this->_endTable();
  18224.                 break;
  18225.             case 'remote-info':
  18226.                 $d = $data;
  18227.                 $data = array(
  18228.                     'caption' => 'Package details:',
  18229.                     'border' => false,
  18230.                     'data' => array(
  18231.                         array("Latest",    $data['stable']),
  18232.                         array("Installed", $data['installed']),
  18233.                         array("Package",   $data['name']),
  18234.                         array("License",   $data['license']),
  18235.                         array("Category",  $data['category']),
  18236.                         array("Summary",   $data['summary']),
  18237.                         array("Description", $data['description']),
  18238.                         ),
  18239.                     );
  18240.                     if (isset($d['deprecated']) && $d['deprecated']) {
  18241.                         $conf = &PEAR_Config::singleton();
  18242.                         $reg = $conf->getRegistry();
  18243.                         $name = $reg->parsedPackageNameToString($d['deprecated'], true);
  18244.                         $data['data'][] = array('Deprecated! use', $name);
  18245.                     }
  18246.             default: {
  18247.                 if (is_array($data)) {
  18248.                     $this->_startTable($data);
  18249.                     $count = count($data['data'][0]);
  18250.                     if ($count == 2) {
  18251.                         $opts = array(0 => array('wrap' => 25),
  18252.                                       1 => array('wrap' => 48)
  18253.                         );
  18254.                     } elseif ($count == 3) {
  18255.                         $opts = array(0 => array('wrap' => 30),
  18256.                                       1 => array('wrap' => 20),
  18257.                                       2 => array('wrap' => 35)
  18258.                         );
  18259.                     } else {
  18260.                         $opts = null;
  18261.                     }
  18262.                     if (isset($data['headline']) && is_array($data['headline'])) {
  18263.                         $this->_tableRow($data['headline'],
  18264.                                          array('bold' => true),
  18265.                                          $opts);
  18266.                     }
  18267.                     foreach($data['data'] as $row) {
  18268.                         $this->_tableRow($row, null, $opts);
  18269.                     }
  18270.                     $this->_endTable();
  18271.                 } else {
  18272.                     $this->_displayLine($data);
  18273.                 }
  18274.             }
  18275.         }
  18276.     }
  18277.  
  18278.     // }}}
  18279.     // {{{ log(text)
  18280.  
  18281.  
  18282.     function log($text, $append_crlf = true)
  18283.     {
  18284.         if ($append_crlf) {
  18285.             return $this->_displayLine($text);
  18286.         }
  18287.         return $this->_display($text);
  18288.     }
  18289.  
  18290.  
  18291.     // }}}
  18292.     // {{{ bold($text)
  18293.  
  18294.     function bold($text)
  18295.     {
  18296.         if (empty($this->term['bold'])) {
  18297.             return strtoupper($text);
  18298.         }
  18299.         return $this->term['bold'] . $text . $this->term['normal'];
  18300.     }
  18301.  
  18302.     // }}}
  18303. }
  18304.  
  18305. ?>
  18306. package.xml100666      0      0        7350 10216370533   6234 <?xml version="1.0" encoding="ISO-8859-1" ?>
  18307. <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
  18308. <package version="1.0">
  18309.   <name>Archive_Tar</name>
  18310.   <summary>Tar file management class</summary>
  18311.   <description>This class provides handling of tar files in PHP.
  18312. It supports creating, listing, extracting and adding to tar files.
  18313. Gzip support is available if PHP has the zlib extension built-in or
  18314. loaded. Bz2 compression is also supported with the bz2 extension loaded.</description>
  18315.   <maintainers>
  18316.     <maintainer>
  18317.       <user>vblavet</user>
  18318.       <name>Vincent Blavet</name>
  18319.       <email>vincent@phpconcept.net</email>
  18320.       <role>lead</role>
  18321.     </maintainer>
  18322.     <maintainer>
  18323.       <user>ssb</user>
  18324.       <name>Stig Bakken</name>
  18325.       <email>stig@php.net</email>
  18326.       <role>helper</role>
  18327.     </maintainer>
  18328.   </maintainers>
  18329.   <release>
  18330.     <version>1.3.1</version>
  18331.     <date>2005-03-17</date>
  18332.     <license>PHP License</license>
  18333.     <state>stable</state>
  18334.     <notes>Correct Bug #3855</notes>
  18335.     <provides type="class" name="Archive_Tar" />
  18336.     <provides type="function" name="Archive_Tar::create" />
  18337.     <provides type="function" name="Archive_Tar::add" />
  18338.     <provides type="function" name="Archive_Tar::extract" />
  18339.     <provides type="function" name="Archive_Tar::listContent" />
  18340.     <provides type="function" name="Archive_Tar::createModify" />
  18341.     <provides type="function" name="Archive_Tar::addModify" />
  18342.     <provides type="function" name="Archive_Tar::addString" />
  18343.     <provides type="function" name="Archive_Tar::extractModify" />
  18344.     <provides type="function" name="Archive_Tar::extractInString" />
  18345.     <provides type="function" name="Archive_Tar::extractList" />
  18346.     <provides type="function" name="Archive_Tar::setAttribute" />
  18347.     <filelist>
  18348.       <file role="php" baseinstalldir="/" md5sum="5a9ef212cbfc1789c875870b3a4db6e5" name="Archive/Tar.php"/>
  18349.       <file role="doc" baseinstalldir="/" md5sum="ae640b797078a6542ea0d236f28efffb" name="docs/Archive_Tar.txt"/>
  18350.     </filelist>
  18351.   </release>
  18352.   <changelog>
  18353.     <release>
  18354.       <version>1.3.0</version>
  18355.       <date>2005-03-06</date>
  18356.       <state>stable</state>
  18357.       <notes>Bugs correction (2475, 2488, 2135, 2176)
  18358.     
  18359. </notes>
  18360.     </release>
  18361.     <release>
  18362.       <version>1.2</version>
  18363.       <date>2004-05-08</date>
  18364.       <state>stable</state>
  18365.       <notes>Add support for other separator than the space char and bug
  18366.     correction
  18367.     
  18368. </notes>
  18369.     </release>
  18370.     <release>
  18371.       <version>1.1</version>
  18372.       <date>2003-05-28</date>
  18373.       <state>stable</state>
  18374.       <notes>* Add support for BZ2 compression
  18375. * Add support for add and extract without using temporary files : methods addString() and extractInString()
  18376. </notes>
  18377.     </release>
  18378.     <release>
  18379.       <version>1.0</version>
  18380.       <date>2003-01-24</date>
  18381.       <state>stable</state>
  18382.       <notes>Change status to stable
  18383.  
  18384. </notes>
  18385.     </release>
  18386.     <release>
  18387.       <version>0.10-b1</version>
  18388.       <date>2003-01-08</date>
  18389.       <state>beta</state>
  18390.       <notes>Add support for long filenames (greater than 99 characters)
  18391.  
  18392. </notes>
  18393.     </release>
  18394.     <release>
  18395.       <version>0.9</version>
  18396.       <date>2002-05-27</date>
  18397.       <state>stable</state>
  18398.       <notes>Auto-detect gzip'ed files
  18399.  
  18400. </notes>
  18401.     </release>
  18402.     <release>
  18403.       <version>0.4</version>
  18404.       <date>2002-05-20</date>
  18405.       <state>stable</state>
  18406.       <notes>Windows bugfix: use forward slashes inside archives
  18407.  
  18408. </notes>
  18409.     </release>
  18410.     <release>
  18411.       <version>0.2</version>
  18412.       <date>2002-02-18</date>
  18413.       <state>stable</state>
  18414.       <notes>From initial commit to stable
  18415.  
  18416. </notes>
  18417.     </release>
  18418.     <release>
  18419.       <version>0.3</version>
  18420.       <date>2002-04-13</date>
  18421.       <state>stable</state>
  18422.       <notes>Windows bugfix: used wrong directory separators
  18423.  
  18424. </notes>
  18425.     </release>
  18426.   </changelog>
  18427. </package>
  18428. Archive_Tar-1.3.1/Archive/Tar.php100666      0      0      166777 10216370147  11650 <?php
  18429. /* vim: set ts=4 sw=4: */
  18430. // +----------------------------------------------------------------------+
  18431. // | PHP Version 4                                                        |
  18432. // +----------------------------------------------------------------------+
  18433. // | Copyright (c) 1997-2003 The PHP Group                                |
  18434. // +----------------------------------------------------------------------+
  18435. // | This source file is subject to version 3.0 of the PHP license,       |
  18436. // | that is bundled with this package in the file LICENSE, and is        |
  18437. // | available through the world-wide-web at the following url:           |
  18438. // | http://www.php.net/license/3_0.txt.                                  |
  18439. // | If you did not receive a copy of the PHP license and are unable to   |
  18440. // | obtain it through the world-wide-web, please send a note to          |
  18441. // | license@php.net so we can mail you a copy immediately.               |
  18442. // +----------------------------------------------------------------------+
  18443. // | Author: Vincent Blavet <vincent@phpconcept.net>                      |
  18444. // +----------------------------------------------------------------------+
  18445. //
  18446. // $Id: Tar.php,v 1.29 2005/03/17 21:02:31 vblavet Exp $
  18447.  
  18448. require_once 'PEAR.php';
  18449.  
  18450.  
  18451. define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
  18452.  
  18453. /**
  18454. * Creates a (compressed) Tar archive
  18455. *
  18456. * @author   Vincent Blavet <vincent@phpconcept.net>
  18457. * @version  $Revision: 1.29 $
  18458. * @package  Archive
  18459. */
  18460. class Archive_Tar extends PEAR
  18461. {
  18462.     /**
  18463.     * @var string Name of the Tar
  18464.     */
  18465.     var $_tarname='';
  18466.  
  18467.     /**
  18468.     * @var boolean if true, the Tar file will be gzipped
  18469.     */
  18470.     var $_compress=false;
  18471.  
  18472.     /**
  18473.     * @var string Type of compression : 'none', 'gz' or 'bz2'
  18474.     */
  18475.     var $_compress_type='none';
  18476.  
  18477.     /**
  18478.     * @var string Explode separator
  18479.     */
  18480.     var $_separator=' ';
  18481.  
  18482.     /**
  18483.     * @var file descriptor
  18484.     */
  18485.     var $_file=0;
  18486.  
  18487.     /**
  18488.     * @var string Local Tar name of a remote Tar (http:// or ftp://)
  18489.     */
  18490.     var $_temp_tarname='';
  18491.  
  18492.     // {{{ constructor
  18493.     /**
  18494.     * Archive_Tar Class constructor. This flavour of the constructor only
  18495.     * declare a new Archive_Tar object, identifying it by the name of the
  18496.     * tar file.
  18497.     * If the compress argument is set the tar will be read or created as a
  18498.     * gzip or bz2 compressed TAR file.
  18499.     *
  18500.     * @param    string  $p_tarname  The name of the tar archive to create
  18501.     * @param    string  $p_compress can be null, 'gz' or 'bz2'. This
  18502.     *                   parameter indicates if gzip or bz2 compression
  18503.     *                   is required.  For compatibility reason the
  18504.     *                   boolean value 'true' means 'gz'.
  18505.     * @access public
  18506.     */
  18507.     function Archive_Tar($p_tarname, $p_compress = null)
  18508.     {
  18509.         $this->PEAR();
  18510.         $this->_compress = false;
  18511.         $this->_compress_type = 'none';
  18512.         if (($p_compress === null) || ($p_compress == '')) {
  18513.             if (@file_exists($p_tarname)) {
  18514.                 if ($fp = @fopen($p_tarname, "rb")) {
  18515.                     // look for gzip magic cookie
  18516.                     $data = fread($fp, 2);
  18517.                     fclose($fp);
  18518.                     if ($data == "\37\213") {
  18519.                         $this->_compress = true;
  18520.                         $this->_compress_type = 'gz';
  18521.                     // No sure it's enought for a magic code ....
  18522.                     } elseif ($data == "BZ") {
  18523.                         $this->_compress = true;
  18524.                         $this->_compress_type = 'bz2';
  18525.                     }
  18526.                 }
  18527.             } else {
  18528.                 // probably a remote file or some file accessible
  18529.                 // through a stream interface
  18530.                 if (substr($p_tarname, -2) == 'gz') {
  18531.                     $this->_compress = true;
  18532.                     $this->_compress_type = 'gz';
  18533.                 } elseif ((substr($p_tarname, -3) == 'bz2') ||
  18534.                           (substr($p_tarname, -2) == 'bz')) {
  18535.                     $this->_compress = true;
  18536.                     $this->_compress_type = 'bz2';
  18537.                 }
  18538.             }
  18539.         } else {
  18540.             if (($p_compress === true) || ($p_compress == 'gz')) {
  18541.                 $this->_compress = true;
  18542.                 $this->_compress_type = 'gz';
  18543.             } else if ($p_compress == 'bz2') {
  18544.                 $this->_compress = true;
  18545.                 $this->_compress_type = 'bz2';
  18546.             } else {
  18547.                 die("Unsupported compression type '$p_compress'\n".
  18548.                     "Supported types are 'gz' and 'bz2'.\n");
  18549.                 return false;
  18550.             }
  18551.         }
  18552.         $this->_tarname = $p_tarname;
  18553.         if ($this->_compress) { // assert zlib or bz2 extension support
  18554.             if ($this->_compress_type == 'gz')
  18555.                 $extname = 'zlib';
  18556.             else if ($this->_compress_type == 'bz2')
  18557.                 $extname = 'bz2';
  18558.  
  18559.             if (!extension_loaded($extname)) {
  18560.                 PEAR::loadExtension($extname);
  18561.             }
  18562.             if (!extension_loaded($extname)) {
  18563.                 die("The extension '$extname' couldn't be found.\n".
  18564.                     "Please make sure your version of PHP was built ".
  18565.                     "with '$extname' support.\n");
  18566.                 return false;
  18567.             }
  18568.         }
  18569.     }
  18570.     // }}}
  18571.  
  18572.     // {{{ destructor
  18573.     function _Archive_Tar()
  18574.     {
  18575.         $this->_close();
  18576.         // ----- Look for a local copy to delete
  18577.         if ($this->_temp_tarname != '')
  18578.             @unlink($this->_temp_tarname);
  18579.         $this->_PEAR();
  18580.     }
  18581.     // }}}
  18582.  
  18583.     // {{{ create()
  18584.     /**
  18585.     * This method creates the archive file and add the files / directories
  18586.     * that are listed in $p_filelist.
  18587.     * If a file with the same name exist and is writable, it is replaced
  18588.     * by the new tar.
  18589.     * The method return false and a PEAR error text.
  18590.     * The $p_filelist parameter can be an array of string, each string
  18591.     * representing a filename or a directory name with their path if
  18592.     * needed. It can also be a single string with names separated by a
  18593.     * single blank.
  18594.     * For each directory added in the archive, the files and
  18595.     * sub-directories are also added.
  18596.     * See also createModify() method for more details.
  18597.     *
  18598.     * @param array  $p_filelist An array of filenames and directory names, or a
  18599.     *                           single string with names separated by a single
  18600.     *                           blank space.
  18601.     * @return                   true on success, false on error.
  18602.     * @see createModify()
  18603.     * @access public
  18604.     */
  18605.     function create($p_filelist)
  18606.     {
  18607.         return $this->createModify($p_filelist, '', '');
  18608.     }
  18609.     // }}}
  18610.  
  18611.     // {{{ add()
  18612.     /**
  18613.     * This method add the files / directories that are listed in $p_filelist in
  18614.     * the archive. If the archive does not exist it is created.
  18615.     * The method return false and a PEAR error text.
  18616.     * The files and directories listed are only added at the end of the archive,
  18617.     * even if a file with the same name is already archived.
  18618.     * See also createModify() method for more details.
  18619.     *
  18620.     * @param array  $p_filelist An array of filenames and directory names, or a
  18621.     *                           single string with names separated by a single
  18622.     *                           blank space.
  18623.     * @return                   true on success, false on error.
  18624.     * @see createModify()
  18625.     * @access public
  18626.     */
  18627.     function add($p_filelist)
  18628.     {
  18629.         return $this->addModify($p_filelist, '', '');
  18630.     }
  18631.     // }}}
  18632.  
  18633.     // {{{ extract()
  18634.     function extract($p_path='')
  18635.     {
  18636.         return $this->extractModify($p_path, '');
  18637.     }
  18638.     // }}}
  18639.  
  18640.     // {{{ listContent()
  18641.     function listContent()
  18642.     {
  18643.         $v_list_detail = array();
  18644.  
  18645.         if ($this->_openRead()) {
  18646.             if (!$this->_extractList('', $v_list_detail, "list", '', '')) {
  18647.                 unset($v_list_detail);
  18648.                 $v_list_detail = 0;
  18649.             }
  18650.             $this->_close();
  18651.         }
  18652.  
  18653.         return $v_list_detail;
  18654.     }
  18655.     // }}}
  18656.  
  18657.     // {{{ createModify()
  18658.     /**
  18659.     * This method creates the archive file and add the files / directories
  18660.     * that are listed in $p_filelist.
  18661.     * If the file already exists and is writable, it is replaced by the
  18662.     * new tar. It is a create and not an add. If the file exists and is
  18663.     * read-only or is a directory it is not replaced. The method return
  18664.     * false and a PEAR error text.
  18665.     * The $p_filelist parameter can be an array of string, each string
  18666.     * representing a filename or a directory name with their path if
  18667.     * needed. It can also be a single string with names separated by a
  18668.     * single blank.
  18669.     * The path indicated in $p_remove_dir will be removed from the
  18670.     * memorized path of each file / directory listed when this path
  18671.     * exists. By default nothing is removed (empty path '')
  18672.     * The path indicated in $p_add_dir will be added at the beginning of
  18673.     * the memorized path of each file / directory listed. However it can
  18674.     * be set to empty ''. The adding of a path is done after the removing
  18675.     * of path.
  18676.     * The path add/remove ability enables the user to prepare an archive
  18677.     * for extraction in a different path than the origin files are.
  18678.     * See also addModify() method for file adding properties.
  18679.     *
  18680.     * @param array  $p_filelist     An array of filenames and directory names,
  18681.     *                               or a single string with names separated by
  18682.     *                               a single blank space.
  18683.     * @param string $p_add_dir      A string which contains a path to be added
  18684.     *                               to the memorized path of each element in
  18685.     *                               the list.
  18686.     * @param string $p_remove_dir   A string which contains a path to be
  18687.     *                               removed from the memorized path of each
  18688.     *                               element in the list, when relevant.
  18689.     * @return boolean               true on success, false on error.
  18690.     * @access public
  18691.     * @see addModify()
  18692.     */
  18693.     function createModify($p_filelist, $p_add_dir, $p_remove_dir='')
  18694.     {
  18695.         $v_result = true;
  18696.  
  18697.         if (!$this->_openWrite())
  18698.             return false;
  18699.  
  18700.         if ($p_filelist != '') {
  18701.             if (is_array($p_filelist))
  18702.                 $v_list = $p_filelist;
  18703.             elseif (is_string($p_filelist))
  18704.                 $v_list = explode($this->_separator, $p_filelist);
  18705.             else {
  18706.                 $this->_cleanFile();
  18707.                 $this->_error('Invalid file list');
  18708.                 return false;
  18709.             }
  18710.  
  18711.             $v_result = $this->_addList($v_list, $p_add_dir, $p_remove_dir);
  18712.         }
  18713.  
  18714.         if ($v_result) {
  18715.             $this->_writeFooter();
  18716.             $this->_close();
  18717.         } else
  18718.             $this->_cleanFile();
  18719.  
  18720.         return $v_result;
  18721.     }
  18722.     // }}}
  18723.  
  18724.     // {{{ addModify()
  18725.     /**
  18726.     * This method add the files / directories listed in $p_filelist at the
  18727.     * end of the existing archive. If the archive does not yet exists it
  18728.     * is created.
  18729.     * The $p_filelist parameter can be an array of string, each string
  18730.     * representing a filename or a directory name with their path if
  18731.     * needed. It can also be a single string with names separated by a
  18732.     * single blank.
  18733.     * The path indicated in $p_remove_dir will be removed from the
  18734.     * memorized path of each file / directory listed when this path
  18735.     * exists. By default nothing is removed (empty path '')
  18736.     * The path indicated in $p_add_dir will be added at the beginning of
  18737.     * the memorized path of each file / directory listed. However it can
  18738.     * be set to empty ''. The adding of a path is done after the removing
  18739.     * of path.
  18740.     * The path add/remove ability enables the user to prepare an archive
  18741.     * for extraction in a different path than the origin files are.
  18742.     * If a file/dir is already in the archive it will only be added at the
  18743.     * end of the archive. There is no update of the existing archived
  18744.     * file/dir. However while extracting the archive, the last file will
  18745.     * replace the first one. This results in a none optimization of the
  18746.     * archive size.
  18747.     * If a file/dir does not exist the file/dir is ignored. However an
  18748.     * error text is send to PEAR error.
  18749.     * If a file/dir is not readable the file/dir is ignored. However an
  18750.     * error text is send to PEAR error.
  18751.     *
  18752.     * @param array      $p_filelist     An array of filenames and directory
  18753.     *                                   names, or a single string with names
  18754.     *                                   separated by a single blank space.
  18755.     * @param string     $p_add_dir      A string which contains a path to be
  18756.     *                                   added to the memorized path of each
  18757.     *                                   element in the list.
  18758.     * @param string     $p_remove_dir   A string which contains a path to be
  18759.     *                                   removed from the memorized path of
  18760.     *                                   each element in the list, when
  18761.     *                                   relevant.
  18762.     * @return                           true on success, false on error.
  18763.     * @access public
  18764.     */
  18765.     function addModify($p_filelist, $p_add_dir, $p_remove_dir='')
  18766.     {
  18767.         $v_result = true;
  18768.  
  18769.         if (!$this->_isArchive())
  18770.             $v_result = $this->createModify($p_filelist, $p_add_dir,
  18771.                                             $p_remove_dir);
  18772.         else {
  18773.             if (is_array($p_filelist))
  18774.                 $v_list = $p_filelist;
  18775.             elseif (is_string($p_filelist))
  18776.                 $v_list = explode($this->_separator, $p_filelist);
  18777.             else {
  18778.                 $this->_error('Invalid file list');
  18779.                 return false;
  18780.             }
  18781.  
  18782.             $v_result = $this->_append($v_list, $p_add_dir, $p_remove_dir);
  18783.         }
  18784.  
  18785.         return $v_result;
  18786.     }
  18787.     // }}}
  18788.  
  18789.     // {{{ addString()
  18790.     /**
  18791.     * This method add a single string as a file at the
  18792.     * end of the existing archive. If the archive does not yet exists it
  18793.     * is created.
  18794.     *
  18795.     * @param string     $p_filename     A string which contains the full
  18796.     *                                   filename path that will be associated
  18797.     *                                   with the string.
  18798.     * @param string     $p_string       The content of the file added in
  18799.     *                                   the archive.
  18800.     * @return                           true on success, false on error.
  18801.     * @access public
  18802.     */
  18803.     function addString($p_filename, $p_string)
  18804.     {
  18805.         $v_result = true;
  18806.         
  18807.         if (!$this->_isArchive()) {
  18808.             if (!$this->_openWrite()) {
  18809.                 return false;
  18810.             }
  18811.             $this->_close();
  18812.         }
  18813.         
  18814.         if (!$this->_openAppend())
  18815.             return false;
  18816.  
  18817.         // Need to check the get back to the temporary file ? ....
  18818.         $v_result = $this->_addString($p_filename, $p_string);
  18819.  
  18820.         $this->_writeFooter();
  18821.  
  18822.         $this->_close();
  18823.  
  18824.         return $v_result;
  18825.     }
  18826.     // }}}
  18827.  
  18828.     // {{{ extractModify()
  18829.     /**
  18830.     * This method extract all the content of the archive in the directory
  18831.     * indicated by $p_path. When relevant the memorized path of the
  18832.     * files/dir can be modified by removing the $p_remove_path path at the
  18833.     * beginning of the file/dir path.
  18834.     * While extracting a file, if the directory path does not exists it is
  18835.     * created.
  18836.     * While extracting a file, if the file already exists it is replaced
  18837.     * without looking for last modification date.
  18838.     * While extracting a file, if the file already exists and is write
  18839.     * protected, the extraction is aborted.
  18840.     * While extracting a file, if a directory with the same name already
  18841.     * exists, the extraction is aborted.
  18842.     * While extracting a directory, if a file with the same name already
  18843.     * exists, the extraction is aborted.
  18844.     * While extracting a file/directory if the destination directory exist
  18845.     * and is write protected, or does not exist but can not be created,
  18846.     * the extraction is aborted.
  18847.     * If after extraction an extracted file does not show the correct
  18848.     * stored file size, the extraction is aborted.
  18849.     * When the extraction is aborted, a PEAR error text is set and false
  18850.     * is returned. However the result can be a partial extraction that may
  18851.     * need to be manually cleaned.
  18852.     *
  18853.     * @param string $p_path         The path of the directory where the
  18854.     *                               files/dir need to by extracted.
  18855.     * @param string $p_remove_path  Part of the memorized path that can be
  18856.     *                               removed if present at the beginning of
  18857.     *                               the file/dir path.
  18858.     * @return boolean               true on success, false on error.
  18859.     * @access public
  18860.     * @see extractList()
  18861.     */
  18862.     function extractModify($p_path, $p_remove_path)
  18863.     {
  18864.         $v_result = true;
  18865.         $v_list_detail = array();
  18866.  
  18867.         if ($v_result = $this->_openRead()) {
  18868.             $v_result = $this->_extractList($p_path, $v_list_detail,
  18869.                                             "complete", 0, $p_remove_path);
  18870.             $this->_close();
  18871.         }
  18872.  
  18873.         return $v_result;
  18874.     }
  18875.     // }}}
  18876.  
  18877.     // {{{ extractInString()
  18878.     /**
  18879.     * This method extract from the archive one file identified by $p_filename.
  18880.     * The return value is a string with the file content, or NULL on error.
  18881.     * @param string $p_filename     The path of the file to extract in a string.
  18882.     * @return                       a string with the file content or NULL.
  18883.     * @access public
  18884.     */
  18885.     function extractInString($p_filename)
  18886.     {
  18887.         if ($this->_openRead()) {
  18888.             $v_result = $this->_extractInString($p_filename);
  18889.             $this->_close();
  18890.         } else {
  18891.             $v_result = NULL;
  18892.         }
  18893.  
  18894.         return $v_result;
  18895.     }
  18896.     // }}}
  18897.  
  18898.     // {{{ extractList()
  18899.     /**
  18900.     * This method extract from the archive only the files indicated in the
  18901.     * $p_filelist. These files are extracted in the current directory or
  18902.     * in the directory indicated by the optional $p_path parameter.
  18903.     * If indicated the $p_remove_path can be used in the same way as it is
  18904.     * used in extractModify() method.
  18905.     * @param array  $p_filelist     An array of filenames and directory names,
  18906.     *                               or a single string with names separated
  18907.     *                               by a single blank space.
  18908.     * @param string $p_path         The path of the directory where the
  18909.     *                               files/dir need to by extracted.
  18910.     * @param string $p_remove_path  Part of the memorized path that can be
  18911.     *                               removed if present at the beginning of
  18912.     *                               the file/dir path.
  18913.     * @return                       true on success, false on error.
  18914.     * @access public
  18915.     * @see extractModify()
  18916.     */
  18917.     function extractList($p_filelist, $p_path='', $p_remove_path='')
  18918.     {
  18919.         $v_result = true;
  18920.         $v_list_detail = array();
  18921.  
  18922.         if (is_array($p_filelist))
  18923.             $v_list = $p_filelist;
  18924.         elseif (is_string($p_filelist))
  18925.             $v_list = explode($this->_separator, $p_filelist);
  18926.         else {
  18927.             $this->_error('Invalid string list');
  18928.             return false;
  18929.         }
  18930.  
  18931.         if ($v_result = $this->_openRead()) {
  18932.             $v_result = $this->_extractList($p_path, $v_list_detail, "partial",
  18933.                                             $v_list, $p_remove_path);
  18934.             $this->_close();
  18935.         }
  18936.  
  18937.         return $v_result;
  18938.     }
  18939.     // }}}
  18940.  
  18941.     // {{{ setAttribute()
  18942.     /**
  18943.     * This method set specific attributes of the archive. It uses a variable
  18944.     * list of parameters, in the format attribute code + attribute values :
  18945.     * $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
  18946.     * @param mixed $argv            variable list of attributes and values
  18947.     * @return                       true on success, false on error.
  18948.     * @access public
  18949.     */
  18950.     function setAttribute()
  18951.     {
  18952.         $v_result = true;
  18953.         
  18954.         // ----- Get the number of variable list of arguments
  18955.         if (($v_size = func_num_args()) == 0) {
  18956.             return true;
  18957.         }
  18958.         
  18959.         // ----- Get the arguments
  18960.         $v_att_list = &func_get_args();
  18961.  
  18962.         // ----- Read the attributes
  18963.         $i=0;
  18964.         while ($i<$v_size) {
  18965.  
  18966.             // ----- Look for next option
  18967.             switch ($v_att_list[$i]) {
  18968.                 // ----- Look for options that request a string value
  18969.                 case ARCHIVE_TAR_ATT_SEPARATOR :
  18970.                     // ----- Check the number of parameters
  18971.                     if (($i+1) >= $v_size) {
  18972.                         $this->_error('Invalid number of parameters for '
  18973.                                       .'attribute ARCHIVE_TAR_ATT_SEPARATOR');
  18974.                         return false;
  18975.                     }
  18976.  
  18977.                     // ----- Get the value
  18978.                     $this->_separator = $v_att_list[$i+1];
  18979.                     $i++;
  18980.                 break;
  18981.  
  18982.                 default :
  18983.                     $this->_error('Unknow attribute code '.$v_att_list[$i].'');
  18984.                     return false;
  18985.             }
  18986.  
  18987.             // ----- Next attribute
  18988.             $i++;
  18989.         }
  18990.  
  18991.         return $v_result;
  18992.     }
  18993.     // }}}
  18994.  
  18995.     // {{{ _error()
  18996.     function _error($p_message)
  18997.     {
  18998.         // ----- To be completed
  18999.         $this->raiseError($p_message);
  19000.     }
  19001.     // }}}
  19002.  
  19003.     // {{{ _warning()
  19004.     function _warning($p_message)
  19005.     {
  19006.         // ----- To be completed
  19007.         $this->raiseError($p_message);
  19008.     }
  19009.     // }}}
  19010.  
  19011.     // {{{ _isArchive()
  19012.     function _isArchive($p_filename=NULL)
  19013.     {
  19014.         if ($p_filename == NULL) {
  19015.             $p_filename = $this->_tarname;
  19016.         }
  19017.         clearstatcache();
  19018.         return @is_file($p_filename);
  19019.     }
  19020.     // }}}
  19021.  
  19022.     // {{{ _openWrite()
  19023.     function _openWrite()
  19024.     {
  19025.         if ($this->_compress_type == 'gz')
  19026.             $this->_file = @gzopen($this->_tarname, "wb9");
  19027.         else if ($this->_compress_type == 'bz2')
  19028.             $this->_file = @bzopen($this->_tarname, "wb");
  19029.         else if ($this->_compress_type == 'none')
  19030.             $this->_file = @fopen($this->_tarname, "wb");
  19031.         else
  19032.             $this->_error('Unknown or missing compression type ('
  19033.                           .$this->_compress_type.')');
  19034.  
  19035.         if ($this->_file == 0) {
  19036.             $this->_error('Unable to open in write mode \''
  19037.                           .$this->_tarname.'\'');
  19038.             return false;
  19039.         }
  19040.  
  19041.         return true;
  19042.     }
  19043.     // }}}
  19044.  
  19045.     // {{{ _openRead()
  19046.     function _openRead()
  19047.     {
  19048.         if (strtolower(substr($this->_tarname, 0, 7)) == 'http://') {
  19049.  
  19050.           // ----- Look if a local copy need to be done
  19051.           if ($this->_temp_tarname == '') {
  19052.               $this->_temp_tarname = uniqid('tar').'.tmp';
  19053.               if (!$v_file_from = @fopen($this->_tarname, 'rb')) {
  19054.                 $this->_error('Unable to open in read mode \''
  19055.                               .$this->_tarname.'\'');
  19056.                 $this->_temp_tarname = '';
  19057.                 return false;
  19058.               }
  19059.               if (!$v_file_to = @fopen($this->_temp_tarname, 'wb')) {
  19060.                 $this->_error('Unable to open in write mode \''
  19061.                               .$this->_temp_tarname.'\'');
  19062.                 $this->_temp_tarname = '';
  19063.                 return false;
  19064.               }
  19065.               while ($v_data = @fread($v_file_from, 1024))
  19066.                   @fwrite($v_file_to, $v_data);
  19067.               @fclose($v_file_from);
  19068.               @fclose($v_file_to);
  19069.           }
  19070.  
  19071.           // ----- File to open if the local copy
  19072.           $v_filename = $this->_temp_tarname;
  19073.  
  19074.         } else
  19075.           // ----- File to open if the normal Tar file
  19076.           $v_filename = $this->_tarname;
  19077.  
  19078.         if ($this->_compress_type == 'gz')
  19079.             $this->_file = @gzopen($v_filename, "rb");
  19080.         else if ($this->_compress_type == 'bz2')
  19081.             $this->_file = @bzopen($v_filename, "rb");
  19082.         else if ($this->_compress_type == 'none')
  19083.             $this->_file = @fopen($v_filename, "rb");
  19084.         else
  19085.             $this->_error('Unknown or missing compression type ('
  19086.                           .$this->_compress_type.')');
  19087.  
  19088.         if ($this->_file == 0) {
  19089.             $this->_error('Unable to open in read mode \''.$v_filename.'\'');
  19090.             return false;
  19091.         }
  19092.  
  19093.         return true;
  19094.     }
  19095.     // }}}
  19096.  
  19097.     // {{{ _openReadWrite()
  19098.     function _openReadWrite()
  19099.     {
  19100.         if ($this->_compress_type == 'gz')
  19101.             $this->_file = @gzopen($this->_tarname, "r+b");
  19102.         else if ($this->_compress_type == 'bz2')
  19103.             $this->_file = @bzopen($this->_tarname, "r+b");
  19104.         else if ($this->_compress_type == 'none')
  19105.             $this->_file = @fopen($this->_tarname, "r+b");
  19106.         else
  19107.             $this->_error('Unknown or missing compression type ('
  19108.                           .$this->_compress_type.')');
  19109.  
  19110.         if ($this->_file == 0) {
  19111.             $this->_error('Unable to open in read/write mode \''
  19112.                           .$this->_tarname.'\'');
  19113.             return false;
  19114.         }
  19115.  
  19116.         return true;
  19117.     }
  19118.     // }}}
  19119.  
  19120.     // {{{ _close()
  19121.     function _close()
  19122.     {
  19123.         //if (isset($this->_file)) {
  19124.         if (is_resource($this->_file)) {
  19125.             if ($this->_compress_type == 'gz')
  19126.                 @gzclose($this->_file);
  19127.             else if ($this->_compress_type == 'bz2')
  19128.                 @bzclose($this->_file);
  19129.             else if ($this->_compress_type == 'none')
  19130.                 @fclose($this->_file);
  19131.             else
  19132.                 $this->_error('Unknown or missing compression type ('
  19133.                               .$this->_compress_type.')');
  19134.  
  19135.             $this->_file = 0;
  19136.         }
  19137.  
  19138.         // ----- Look if a local copy need to be erase
  19139.         // Note that it might be interesting to keep the url for a time : ToDo
  19140.         if ($this->_temp_tarname != '') {
  19141.             @unlink($this->_temp_tarname);
  19142.             $this->_temp_tarname = '';
  19143.         }
  19144.  
  19145.         return true;
  19146.     }
  19147.     // }}}
  19148.  
  19149.     // {{{ _cleanFile()
  19150.     function _cleanFile()
  19151.     {
  19152.         $this->_close();
  19153.  
  19154.         // ----- Look for a local copy
  19155.         if ($this->_temp_tarname != '') {
  19156.             // ----- Remove the local copy but not the remote tarname
  19157.             @unlink($this->_temp_tarname);
  19158.             $this->_temp_tarname = '';
  19159.         } else {
  19160.             // ----- Remove the local tarname file
  19161.             @unlink($this->_tarname);
  19162.         }
  19163.         $this->_tarname = '';
  19164.  
  19165.         return true;
  19166.     }
  19167.     // }}}
  19168.  
  19169.     // {{{ _writeBlock()
  19170.     function _writeBlock($p_binary_data, $p_len=null)
  19171.     {
  19172.       if (is_resource($this->_file)) {
  19173.           if ($p_len === null) {
  19174.               if ($this->_compress_type == 'gz')
  19175.                   @gzputs($this->_file, $p_binary_data);
  19176.               else if ($this->_compress_type == 'bz2')
  19177.                   @bzwrite($this->_file, $p_binary_data);
  19178.               else if ($this->_compress_type == 'none')
  19179.                   @fputs($this->_file, $p_binary_data);
  19180.               else
  19181.                   $this->_error('Unknown or missing compression type ('
  19182.                                 .$this->_compress_type.')');
  19183.           } else {
  19184.               if ($this->_compress_type == 'gz')
  19185.                   @gzputs($this->_file, $p_binary_data, $p_len);
  19186.               else if ($this->_compress_type == 'bz2')
  19187.                   @bzwrite($this->_file, $p_binary_data, $p_len);
  19188.               else if ($this->_compress_type == 'none')
  19189.                   @fputs($this->_file, $p_binary_data, $p_len);
  19190.               else
  19191.                   $this->_error('Unknown or missing compression type ('
  19192.                                 .$this->_compress_type.')');
  19193.  
  19194.           }
  19195.       }
  19196.       return true;
  19197.     }
  19198.     // }}}
  19199.  
  19200.     // {{{ _readBlock()
  19201.     function _readBlock()
  19202.     {
  19203.       $v_block = null;
  19204.       if (is_resource($this->_file)) {
  19205.           if ($this->_compress_type == 'gz')
  19206.               $v_block = @gzread($this->_file, 512);
  19207.           else if ($this->_compress_type == 'bz2')
  19208.               $v_block = @bzread($this->_file, 512);
  19209.           else if ($this->_compress_type == 'none')
  19210.               $v_block = @fread($this->_file, 512);
  19211.           else
  19212.               $this->_error('Unknown or missing compression type ('
  19213.                             .$this->_compress_type.')');
  19214.       }
  19215.       return $v_block;
  19216.     }
  19217.     // }}}
  19218.  
  19219.     // {{{ _jumpBlock()
  19220.     function _jumpBlock($p_len=null)
  19221.     {
  19222.       if (is_resource($this->_file)) {
  19223.           if ($p_len === null)
  19224.               $p_len = 1;
  19225.  
  19226.           if ($this->_compress_type == 'gz') {
  19227.               @gzseek($this->_file, @gztell($this->_file)+($p_len*512));
  19228.           }
  19229.           else if ($this->_compress_type == 'bz2') {
  19230.               // ----- Replace missing bztell() and bzseek()
  19231.               for ($i=0; $i<$p_len; $i++)
  19232.                   $this->_readBlock();
  19233.           } else if ($this->_compress_type == 'none')
  19234.               @fseek($this->_file, @ftell($this->_file)+($p_len*512));
  19235.           else
  19236.               $this->_error('Unknown or missing compression type ('
  19237.                             .$this->_compress_type.')');
  19238.  
  19239.       }
  19240.       return true;
  19241.     }
  19242.     // }}}
  19243.  
  19244.     // {{{ _writeFooter()
  19245.     function _writeFooter()
  19246.     {
  19247.       if (is_resource($this->_file)) {
  19248.           // ----- Write the last 0 filled block for end of archive
  19249.           $v_binary_data = pack("a512", '');
  19250.           $this->_writeBlock($v_binary_data);
  19251.       }
  19252.       return true;
  19253.     }
  19254.     // }}}
  19255.  
  19256.     // {{{ _addList()
  19257.     function _addList($p_list, $p_add_dir, $p_remove_dir)
  19258.     {
  19259.       $v_result=true;
  19260.       $v_header = array();
  19261.  
  19262.       // ----- Remove potential windows directory separator
  19263.       $p_add_dir = $this->_translateWinPath($p_add_dir);
  19264.       $p_remove_dir = $this->_translateWinPath($p_remove_dir, false);
  19265.  
  19266.       if (!$this->_file) {
  19267.           $this->_error('Invalid file descriptor');
  19268.           return false;
  19269.       }
  19270.  
  19271.       if (sizeof($p_list) == 0)
  19272.           return true;
  19273.  
  19274.       foreach ($p_list as $v_filename) {
  19275.           if (!$v_result) {
  19276.               break;
  19277.           }
  19278.  
  19279.         // ----- Skip the current tar name
  19280.         if ($v_filename == $this->_tarname)
  19281.             continue;
  19282.  
  19283.         if ($v_filename == '')
  19284.             continue;
  19285.  
  19286.         if (!file_exists($v_filename)) {
  19287.             $this->_warning("File '$v_filename' does not exist");
  19288.             continue;
  19289.         }
  19290.  
  19291.         // ----- Add the file or directory header
  19292.         if (!$this->_addFile($v_filename, $v_header, $p_add_dir, $p_remove_dir))
  19293.             return false;
  19294.  
  19295.         if (@is_dir($v_filename)) {
  19296.             if (!($p_hdir = opendir($v_filename))) {
  19297.                 $this->_warning("Directory '$v_filename' can not be read");
  19298.                 continue;
  19299.             }
  19300.             while (false !== ($p_hitem = readdir($p_hdir))) {
  19301.                 if (($p_hitem != '.') && ($p_hitem != '..')) {
  19302.                     if ($v_filename != ".")
  19303.                         $p_temp_list[0] = $v_filename.'/'.$p_hitem;
  19304.                     else
  19305.                         $p_temp_list[0] = $p_hitem;
  19306.  
  19307.                     $v_result = $this->_addList($p_temp_list,
  19308.                                                 $p_add_dir,
  19309.                                                 $p_remove_dir);
  19310.                 }
  19311.             }
  19312.  
  19313.             unset($p_temp_list);
  19314.             unset($p_hdir);
  19315.             unset($p_hitem);
  19316.         }
  19317.       }
  19318.  
  19319.       return $v_result;
  19320.     }
  19321.     // }}}
  19322.  
  19323.     // {{{ _addFile()
  19324.     function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir)
  19325.     {
  19326.       if (!$this->_file) {
  19327.           $this->_error('Invalid file descriptor');
  19328.           return false;
  19329.       }
  19330.  
  19331.       if ($p_filename == '') {
  19332.           $this->_error('Invalid file name');
  19333.           return false;
  19334.       }
  19335.  
  19336.       // ----- Calculate the stored filename
  19337.       $p_filename = $this->_translateWinPath($p_filename, false);;
  19338.       $v_stored_filename = $p_filename;
  19339.       if (strcmp($p_filename, $p_remove_dir) == 0) {
  19340.           return true;
  19341.       }
  19342.       if ($p_remove_dir != '') {
  19343.           if (substr($p_remove_dir, -1) != '/')
  19344.               $p_remove_dir .= '/';
  19345.  
  19346.           if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir)
  19347.               $v_stored_filename = substr($p_filename, strlen($p_remove_dir));
  19348.       }
  19349.       $v_stored_filename = $this->_translateWinPath($v_stored_filename);
  19350.       if ($p_add_dir != '') {
  19351.           if (substr($p_add_dir, -1) == '/')
  19352.               $v_stored_filename = $p_add_dir.$v_stored_filename;
  19353.           else
  19354.               $v_stored_filename = $p_add_dir.'/'.$v_stored_filename;
  19355.       }
  19356.  
  19357.       $v_stored_filename = $this->_pathReduction($v_stored_filename);
  19358.  
  19359.       if ($this->_isArchive($p_filename)) {
  19360.           if (($v_file = @fopen($p_filename, "rb")) == 0) {
  19361.               $this->_warning("Unable to open file '".$p_filename
  19362.                               ."' in binary read mode");
  19363.               return true;
  19364.           }
  19365.  
  19366.           if (!$this->_writeHeader($p_filename, $v_stored_filename))
  19367.               return false;
  19368.  
  19369.           while (($v_buffer = fread($v_file, 512)) != '') {
  19370.               $v_binary_data = pack("a512", "$v_buffer");
  19371.               $this->_writeBlock($v_binary_data);
  19372.           }
  19373.  
  19374.           fclose($v_file);
  19375.  
  19376.       } else {
  19377.           // ----- Only header for dir
  19378.           if (!$this->_writeHeader($p_filename, $v_stored_filename))
  19379.               return false;
  19380.       }
  19381.  
  19382.       return true;
  19383.     }
  19384.     // }}}
  19385.  
  19386.     // {{{ _addString()
  19387.     function _addString($p_filename, $p_string)
  19388.     {
  19389.       if (!$this->_file) {
  19390.           $this->_error('Invalid file descriptor');
  19391.           return false;
  19392.       }
  19393.  
  19394.       if ($p_filename == '') {
  19395.           $this->_error('Invalid file name');
  19396.           return false;
  19397.       }
  19398.  
  19399.       // ----- Calculate the stored filename
  19400.       $p_filename = $this->_translateWinPath($p_filename, false);;
  19401.  
  19402.       if (!$this->_writeHeaderBlock($p_filename, strlen($p_string),
  19403.                                     0, 0, "", 0, 0))
  19404.           return false;
  19405.  
  19406.       $i=0;
  19407.       while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
  19408.           $v_binary_data = pack("a512", $v_buffer);
  19409.           $this->_writeBlock($v_binary_data);
  19410.       }
  19411.  
  19412.       return true;
  19413.     }
  19414.     // }}}
  19415.  
  19416.     // {{{ _writeHeader()
  19417.     function _writeHeader($p_filename, $p_stored_filename)
  19418.     {
  19419.         if ($p_stored_filename == '')
  19420.             $p_stored_filename = $p_filename;
  19421.         $v_reduce_filename = $this->_pathReduction($p_stored_filename);
  19422.  
  19423.         if (strlen($v_reduce_filename) > 99) {
  19424.           if (!$this->_writeLongHeader($v_reduce_filename))
  19425.             return false;
  19426.         }
  19427.  
  19428.         $v_info = stat($p_filename);
  19429.         $v_uid = sprintf("%6s ", DecOct($v_info[4]));
  19430.         $v_gid = sprintf("%6s ", DecOct($v_info[5]));
  19431.         $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename)));
  19432.  
  19433.         $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename)));
  19434.  
  19435.         if (@is_dir($p_filename)) {
  19436.           $v_typeflag = "5";
  19437.           $v_size = sprintf("%11s ", DecOct(0));
  19438.         } else {
  19439.           $v_typeflag = '';
  19440.           clearstatcache();
  19441.           $v_size = sprintf("%11s ", DecOct(filesize($p_filename)));
  19442.         }
  19443.  
  19444.         $v_linkname = '';
  19445.  
  19446.         $v_magic = '';
  19447.  
  19448.         $v_version = '';
  19449.  
  19450.         $v_uname = '';
  19451.  
  19452.         $v_gname = '';
  19453.  
  19454.         $v_devmajor = '';
  19455.  
  19456.         $v_devminor = '';
  19457.  
  19458.         $v_prefix = '';
  19459.  
  19460.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  19461.                                     $v_reduce_filename, $v_perms, $v_uid,
  19462.                                     $v_gid, $v_size, $v_mtime);
  19463.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  19464.                                    $v_typeflag, $v_linkname, $v_magic,
  19465.                                    $v_version, $v_uname, $v_gname,
  19466.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  19467.  
  19468.         // ----- Calculate the checksum
  19469.         $v_checksum = 0;
  19470.         // ..... First part of the header
  19471.         for ($i=0; $i<148; $i++)
  19472.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  19473.         // ..... Ignore the checksum value and replace it by ' ' (space)
  19474.         for ($i=148; $i<156; $i++)
  19475.             $v_checksum += ord(' ');
  19476.         // ..... Last part of the header
  19477.         for ($i=156, $j=0; $i<512; $i++, $j++)
  19478.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  19479.  
  19480.         // ----- Write the first 148 bytes of the header in the archive
  19481.         $this->_writeBlock($v_binary_data_first, 148);
  19482.  
  19483.         // ----- Write the calculated checksum
  19484.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  19485.         $v_binary_data = pack("a8", $v_checksum);
  19486.         $this->_writeBlock($v_binary_data, 8);
  19487.  
  19488.         // ----- Write the last 356 bytes of the header in the archive
  19489.         $this->_writeBlock($v_binary_data_last, 356);
  19490.  
  19491.         return true;
  19492.     }
  19493.     // }}}
  19494.  
  19495.     // {{{ _writeHeaderBlock()
  19496.     function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0,
  19497.                                $p_type='', $p_uid=0, $p_gid=0)
  19498.     {
  19499.         $p_filename = $this->_pathReduction($p_filename);
  19500.  
  19501.         if (strlen($p_filename) > 99) {
  19502.           if (!$this->_writeLongHeader($p_filename))
  19503.             return false;
  19504.         }
  19505.  
  19506.         if ($p_type == "5") {
  19507.           $v_size = sprintf("%11s ", DecOct(0));
  19508.         } else {
  19509.           $v_size = sprintf("%11s ", DecOct($p_size));
  19510.         }
  19511.  
  19512.         $v_uid = sprintf("%6s ", DecOct($p_uid));
  19513.         $v_gid = sprintf("%6s ", DecOct($p_gid));
  19514.         $v_perms = sprintf("%6s ", DecOct($p_perms));
  19515.  
  19516.         $v_mtime = sprintf("%11s", DecOct($p_mtime));
  19517.  
  19518.         $v_linkname = '';
  19519.  
  19520.         $v_magic = '';
  19521.  
  19522.         $v_version = '';
  19523.  
  19524.         $v_uname = '';
  19525.  
  19526.         $v_gname = '';
  19527.  
  19528.         $v_devmajor = '';
  19529.  
  19530.         $v_devminor = '';
  19531.  
  19532.         $v_prefix = '';
  19533.  
  19534.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  19535.                                     $p_filename, $v_perms, $v_uid, $v_gid,
  19536.                                     $v_size, $v_mtime);
  19537.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  19538.                                    $p_type, $v_linkname, $v_magic,
  19539.                                    $v_version, $v_uname, $v_gname,
  19540.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  19541.  
  19542.         // ----- Calculate the checksum
  19543.         $v_checksum = 0;
  19544.         // ..... First part of the header
  19545.         for ($i=0; $i<148; $i++)
  19546.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  19547.         // ..... Ignore the checksum value and replace it by ' ' (space)
  19548.         for ($i=148; $i<156; $i++)
  19549.             $v_checksum += ord(' ');
  19550.         // ..... Last part of the header
  19551.         for ($i=156, $j=0; $i<512; $i++, $j++)
  19552.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  19553.  
  19554.         // ----- Write the first 148 bytes of the header in the archive
  19555.         $this->_writeBlock($v_binary_data_first, 148);
  19556.  
  19557.         // ----- Write the calculated checksum
  19558.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  19559.         $v_binary_data = pack("a8", $v_checksum);
  19560.         $this->_writeBlock($v_binary_data, 8);
  19561.  
  19562.         // ----- Write the last 356 bytes of the header in the archive
  19563.         $this->_writeBlock($v_binary_data_last, 356);
  19564.  
  19565.         return true;
  19566.     }
  19567.     // }}}
  19568.  
  19569.     // {{{ _writeLongHeader()
  19570.     function _writeLongHeader($p_filename)
  19571.     {
  19572.         $v_size = sprintf("%11s ", DecOct(strlen($p_filename)));
  19573.  
  19574.         $v_typeflag = 'L';
  19575.  
  19576.         $v_linkname = '';
  19577.  
  19578.         $v_magic = '';
  19579.  
  19580.         $v_version = '';
  19581.  
  19582.         $v_uname = '';
  19583.  
  19584.         $v_gname = '';
  19585.  
  19586.         $v_devmajor = '';
  19587.  
  19588.         $v_devminor = '';
  19589.  
  19590.         $v_prefix = '';
  19591.  
  19592.         $v_binary_data_first = pack("a100a8a8a8a12A12",
  19593.                                     '././@LongLink', 0, 0, 0, $v_size, 0);
  19594.         $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12",
  19595.                                    $v_typeflag, $v_linkname, $v_magic,
  19596.                                    $v_version, $v_uname, $v_gname,
  19597.                                    $v_devmajor, $v_devminor, $v_prefix, '');
  19598.  
  19599.         // ----- Calculate the checksum
  19600.         $v_checksum = 0;
  19601.         // ..... First part of the header
  19602.         for ($i=0; $i<148; $i++)
  19603.             $v_checksum += ord(substr($v_binary_data_first,$i,1));
  19604.         // ..... Ignore the checksum value and replace it by ' ' (space)
  19605.         for ($i=148; $i<156; $i++)
  19606.             $v_checksum += ord(' ');
  19607.         // ..... Last part of the header
  19608.         for ($i=156, $j=0; $i<512; $i++, $j++)
  19609.             $v_checksum += ord(substr($v_binary_data_last,$j,1));
  19610.  
  19611.         // ----- Write the first 148 bytes of the header in the archive
  19612.         $this->_writeBlock($v_binary_data_first, 148);
  19613.  
  19614.         // ----- Write the calculated checksum
  19615.         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
  19616.         $v_binary_data = pack("a8", $v_checksum);
  19617.         $this->_writeBlock($v_binary_data, 8);
  19618.  
  19619.         // ----- Write the last 356 bytes of the header in the archive
  19620.         $this->_writeBlock($v_binary_data_last, 356);
  19621.  
  19622.         // ----- Write the filename as content of the block
  19623.         $i=0;
  19624.         while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
  19625.             $v_binary_data = pack("a512", "$v_buffer");
  19626.             $this->_writeBlock($v_binary_data);
  19627.         }
  19628.  
  19629.         return true;
  19630.     }
  19631.     // }}}
  19632.  
  19633.     // {{{ _readHeader()
  19634.     function _readHeader($v_binary_data, &$v_header)
  19635.     {
  19636.         if (strlen($v_binary_data)==0) {
  19637.             $v_header['filename'] = '';
  19638.             return true;
  19639.         }
  19640.  
  19641.         if (strlen($v_binary_data) != 512) {
  19642.             $v_header['filename'] = '';
  19643.             $this->_error('Invalid block size : '.strlen($v_binary_data));
  19644.             return false;
  19645.         }
  19646.  
  19647.         // ----- Calculate the checksum
  19648.         $v_checksum = 0;
  19649.         // ..... First part of the header
  19650.         for ($i=0; $i<148; $i++)
  19651.             $v_checksum+=ord(substr($v_binary_data,$i,1));
  19652.         // ..... Ignore the checksum value and replace it by ' ' (space)
  19653.         for ($i=148; $i<156; $i++)
  19654.             $v_checksum += ord(' ');
  19655.         // ..... Last part of the header
  19656.         for ($i=156; $i<512; $i++)
  19657.            $v_checksum+=ord(substr($v_binary_data,$i,1));
  19658.  
  19659.         $v_data = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/"
  19660.                          ."a8checksum/a1typeflag/a100link/a6magic/a2version/"
  19661.                          ."a32uname/a32gname/a8devmajor/a8devminor",
  19662.                          $v_binary_data);
  19663.  
  19664.         // ----- Extract the checksum
  19665.         $v_header['checksum'] = OctDec(trim($v_data['checksum']));
  19666.         if ($v_header['checksum'] != $v_checksum) {
  19667.             $v_header['filename'] = '';
  19668.  
  19669.             // ----- Look for last block (empty block)
  19670.             if (($v_checksum == 256) && ($v_header['checksum'] == 0))
  19671.                 return true;
  19672.  
  19673.             $this->_error('Invalid checksum for file "'.$v_data['filename']
  19674.                           .'" : '.$v_checksum.' calculated, '
  19675.                           .$v_header['checksum'].' expected');
  19676.             return false;
  19677.         }
  19678.  
  19679.         // ----- Extract the properties
  19680.         $v_header['filename'] = trim($v_data['filename']);
  19681.         $v_header['mode'] = OctDec(trim($v_data['mode']));
  19682.         $v_header['uid'] = OctDec(trim($v_data['uid']));
  19683.         $v_header['gid'] = OctDec(trim($v_data['gid']));
  19684.         $v_header['size'] = OctDec(trim($v_data['size']));
  19685.         $v_header['mtime'] = OctDec(trim($v_data['mtime']));
  19686.         if (($v_header['typeflag'] = $v_data['typeflag']) == "5") {
  19687.           $v_header['size'] = 0;
  19688.         }
  19689.         /* ----- All these fields are removed form the header because
  19690.         they do not carry interesting info
  19691.         $v_header[link] = trim($v_data[link]);
  19692.         $v_header[magic] = trim($v_data[magic]);
  19693.         $v_header[version] = trim($v_data[version]);
  19694.         $v_header[uname] = trim($v_data[uname]);
  19695.         $v_header[gname] = trim($v_data[gname]);
  19696.         $v_header[devmajor] = trim($v_data[devmajor]);
  19697.         $v_header[devminor] = trim($v_data[devminor]);
  19698.         */
  19699.  
  19700.         return true;
  19701.     }
  19702.     // }}}
  19703.  
  19704.     // {{{ _readLongHeader()
  19705.     function _readLongHeader(&$v_header)
  19706.     {
  19707.       $v_filename = '';
  19708.       $n = floor($v_header['size']/512);
  19709.       for ($i=0; $i<$n; $i++) {
  19710.         $v_content = $this->_readBlock();
  19711.         $v_filename .= $v_content;
  19712.       }
  19713.       if (($v_header['size'] % 512) != 0) {
  19714.         $v_content = $this->_readBlock();
  19715.         $v_filename .= $v_content;
  19716.       }
  19717.  
  19718.       // ----- Read the next header
  19719.       $v_binary_data = $this->_readBlock();
  19720.  
  19721.       if (!$this->_readHeader($v_binary_data, $v_header))
  19722.         return false;
  19723.  
  19724.       $v_header['filename'] = $v_filename;
  19725.  
  19726.       return true;
  19727.     }
  19728.     // }}}
  19729.  
  19730.     // {{{ _extractInString()
  19731.     /**
  19732.     * This method extract from the archive one file identified by $p_filename.
  19733.     * The return value is a string with the file content, or NULL on error.
  19734.     * @param string $p_filename     The path of the file to extract in a string.
  19735.     * @return                       a string with the file content or NULL.
  19736.     * @access private
  19737.     */
  19738.     function _extractInString($p_filename)
  19739.     {
  19740.         $v_result_str = "";
  19741.  
  19742.         While (strlen($v_binary_data = $this->_readBlock()) != 0)
  19743.         {
  19744.           if (!$this->_readHeader($v_binary_data, $v_header))
  19745.             return NULL;
  19746.  
  19747.           if ($v_header['filename'] == '')
  19748.             continue;
  19749.  
  19750.           // ----- Look for long filename
  19751.           if ($v_header['typeflag'] == 'L') {
  19752.             if (!$this->_readLongHeader($v_header))
  19753.               return NULL;
  19754.           }
  19755.  
  19756.           if ($v_header['filename'] == $p_filename) {
  19757.               if ($v_header['typeflag'] == "5") {
  19758.                   $this->_error('Unable to extract in string a directory '
  19759.                                 .'entry {'.$v_header['filename'].'}');
  19760.                   return NULL;
  19761.               } else {
  19762.                   $n = floor($v_header['size']/512);
  19763.                   for ($i=0; $i<$n; $i++) {
  19764.                       $v_result_str .= $this->_readBlock();
  19765.                   }
  19766.                   if (($v_header['size'] % 512) != 0) {
  19767.                       $v_content = $this->_readBlock();
  19768.                       $v_result_str .= substr($v_content, 0,
  19769.                                               ($v_header['size'] % 512));
  19770.                   }
  19771.                   return $v_result_str;
  19772.               }
  19773.           } else {
  19774.               $this->_jumpBlock(ceil(($v_header['size']/512)));
  19775.           }
  19776.         }
  19777.  
  19778.         return NULL;
  19779.     }
  19780.     // }}}
  19781.  
  19782.     // {{{ _extractList()
  19783.     function _extractList($p_path, &$p_list_detail, $p_mode,
  19784.                           $p_file_list, $p_remove_path)
  19785.     {
  19786.     $v_result=true;
  19787.     $v_nb = 0;
  19788.     $v_extract_all = true;
  19789.     $v_listing = false;
  19790.  
  19791.     $p_path = $this->_translateWinPath($p_path, false);
  19792.     if ($p_path == '' || (substr($p_path, 0, 1) != '/'
  19793.         && substr($p_path, 0, 3) != "../" && !strpos($p_path, ':'))) {
  19794.       $p_path = "./".$p_path;
  19795.     }
  19796.     $p_remove_path = $this->_translateWinPath($p_remove_path);
  19797.  
  19798.     // ----- Look for path to remove format (should end by /)
  19799.     if (($p_remove_path != '') && (substr($p_remove_path, -1) != '/'))
  19800.       $p_remove_path .= '/';
  19801.     $p_remove_path_size = strlen($p_remove_path);
  19802.  
  19803.     switch ($p_mode) {
  19804.       case "complete" :
  19805.         $v_extract_all = TRUE;
  19806.         $v_listing = FALSE;
  19807.       break;
  19808.       case "partial" :
  19809.           $v_extract_all = FALSE;
  19810.           $v_listing = FALSE;
  19811.       break;
  19812.       case "list" :
  19813.           $v_extract_all = FALSE;
  19814.           $v_listing = TRUE;
  19815.       break;
  19816.       default :
  19817.         $this->_error('Invalid extract mode ('.$p_mode.')');
  19818.         return false;
  19819.     }
  19820.  
  19821.     clearstatcache();
  19822.  
  19823.     while (strlen($v_binary_data = $this->_readBlock()) != 0)
  19824.     {
  19825.       $v_extract_file = FALSE;
  19826.       $v_extraction_stopped = 0;
  19827.  
  19828.       if (!$this->_readHeader($v_binary_data, $v_header))
  19829.         return false;
  19830.  
  19831.       if ($v_header['filename'] == '') {
  19832.         continue;
  19833.       }
  19834.  
  19835.       // ----- Look for long filename
  19836.       if ($v_header['typeflag'] == 'L') {
  19837.         if (!$this->_readLongHeader($v_header))
  19838.           return false;
  19839.       }
  19840.  
  19841.       if ((!$v_extract_all) && (is_array($p_file_list))) {
  19842.         // ----- By default no unzip if the file is not found
  19843.         $v_extract_file = false;
  19844.  
  19845.         for ($i=0; $i<sizeof($p_file_list); $i++) {
  19846.           // ----- Look if it is a directory
  19847.           if (substr($p_file_list[$i], -1) == '/') {
  19848.             // ----- Look if the directory is in the filename path
  19849.             if ((strlen($v_header['filename']) > strlen($p_file_list[$i]))
  19850.                 && (substr($v_header['filename'], 0, strlen($p_file_list[$i]))
  19851.                     == $p_file_list[$i])) {
  19852.               $v_extract_file = TRUE;
  19853.               break;
  19854.             }
  19855.           }
  19856.  
  19857.           // ----- It is a file, so compare the file names
  19858.           elseif ($p_file_list[$i] == $v_header['filename']) {
  19859.             $v_extract_file = TRUE;
  19860.             break;
  19861.           }
  19862.         }
  19863.       } else {
  19864.         $v_extract_file = TRUE;
  19865.       }
  19866.  
  19867.       // ----- Look if this file need to be extracted
  19868.       if (($v_extract_file) && (!$v_listing))
  19869.       {
  19870.         if (($p_remove_path != '')
  19871.             && (substr($v_header['filename'], 0, $p_remove_path_size)
  19872.                 == $p_remove_path))
  19873.           $v_header['filename'] = substr($v_header['filename'],
  19874.                                          $p_remove_path_size);
  19875.         if (($p_path != './') && ($p_path != '/')) {
  19876.           while (substr($p_path, -1) == '/')
  19877.             $p_path = substr($p_path, 0, strlen($p_path)-1);
  19878.  
  19879.           if (substr($v_header['filename'], 0, 1) == '/')
  19880.               $v_header['filename'] = $p_path.$v_header['filename'];
  19881.           else
  19882.             $v_header['filename'] = $p_path.'/'.$v_header['filename'];
  19883.         }
  19884.         if (file_exists($v_header['filename'])) {
  19885.           if (   (@is_dir($v_header['filename']))
  19886.               && ($v_header['typeflag'] == '')) {
  19887.             $this->_error('File '.$v_header['filename']
  19888.                           .' already exists as a directory');
  19889.             return false;
  19890.           }
  19891.           if (   ($this->_isArchive($v_header['filename']))
  19892.               && ($v_header['typeflag'] == "5")) {
  19893.             $this->_error('Directory '.$v_header['filename']
  19894.                           .' already exists as a file');
  19895.             return false;
  19896.           }
  19897.           if (!is_writeable($v_header['filename'])) {
  19898.             $this->_error('File '.$v_header['filename']
  19899.                           .' already exists and is write protected');
  19900.             return false;
  19901.           }
  19902.           if (filemtime($v_header['filename']) > $v_header['mtime']) {
  19903.             // To be completed : An error or silent no replace ?
  19904.           }
  19905.         }
  19906.  
  19907.         // ----- Check the directory availability and create it if necessary
  19908.         elseif (($v_result
  19909.                  = $this->_dirCheck(($v_header['typeflag'] == "5"
  19910.                                     ?$v_header['filename']
  19911.                                     :dirname($v_header['filename'])))) != 1) {
  19912.             $this->_error('Unable to create path for '.$v_header['filename']);
  19913.             return false;
  19914.         }
  19915.  
  19916.         if ($v_extract_file) {
  19917.           if ($v_header['typeflag'] == "5") {
  19918.             if (!@file_exists($v_header['filename'])) {
  19919.                 if (!@mkdir($v_header['filename'], 0777)) {
  19920.                     $this->_error('Unable to create directory {'
  19921.                                   .$v_header['filename'].'}');
  19922.                     return false;
  19923.                 }
  19924.             }
  19925.           } else {
  19926.               if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) {
  19927.                   $this->_error('Error while opening {'.$v_header['filename']
  19928.                                 .'} in write binary mode');
  19929.                   return false;
  19930.               } else {
  19931.                   $n = floor($v_header['size']/512);
  19932.                   for ($i=0; $i<$n; $i++) {
  19933.                       $v_content = $this->_readBlock();
  19934.                       fwrite($v_dest_file, $v_content, 512);
  19935.                   }
  19936.             if (($v_header['size'] % 512) != 0) {
  19937.               $v_content = $this->_readBlock();
  19938.               fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
  19939.             }
  19940.  
  19941.             @fclose($v_dest_file);
  19942.  
  19943.             // ----- Change the file mode, mtime
  19944.             @touch($v_header['filename'], $v_header['mtime']);
  19945.             // To be completed
  19946.             //chmod($v_header[filename], DecOct($v_header[mode]));
  19947.           }
  19948.  
  19949.           // ----- Check the file size
  19950.           clearstatcache();
  19951.           if (filesize($v_header['filename']) != $v_header['size']) {
  19952.               $this->_error('Extracted file '.$v_header['filename']
  19953.                             .' does not have the correct file size \''
  19954.                             .filesize($v_header['filename'])
  19955.                             .'\' ('.$v_header['size']
  19956.                             .' expected). Archive may be corrupted.');
  19957.               return false;
  19958.           }
  19959.           }
  19960.         } else {
  19961.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  19962.         }
  19963.       } else {
  19964.           $this->_jumpBlock(ceil(($v_header['size']/512)));
  19965.       }
  19966.  
  19967.       /* TBC : Seems to be unused ...
  19968.       if ($this->_compress)
  19969.         $v_end_of_file = @gzeof($this->_file);
  19970.       else
  19971.         $v_end_of_file = @feof($this->_file);
  19972.         */
  19973.  
  19974.       if ($v_listing || $v_extract_file || $v_extraction_stopped) {
  19975.         // ----- Log extracted files
  19976.         if (($v_file_dir = dirname($v_header['filename']))
  19977.             == $v_header['filename'])
  19978.           $v_file_dir = '';
  19979.         if ((substr($v_header['filename'], 0, 1) == '/') && ($v_file_dir == ''))
  19980.           $v_file_dir = '/';
  19981.  
  19982.         $p_list_detail[$v_nb++] = $v_header;
  19983.       }
  19984.     }
  19985.  
  19986.         return true;
  19987.     }
  19988.     // }}}
  19989.  
  19990.     // {{{ _openAppend()
  19991.     function _openAppend()
  19992.     {
  19993.         if (filesize($this->_tarname) == 0)
  19994.           return $this->_openWrite();
  19995.           
  19996.         if ($this->_compress) {
  19997.             $this->_close();
  19998.  
  19999.             if (!@rename($this->_tarname, $this->_tarname.".tmp")) {
  20000.                 $this->_error('Error while renaming \''.$this->_tarname
  20001.                               .'\' to temporary file \''.$this->_tarname
  20002.                               .'.tmp\'');
  20003.                 return false;
  20004.             }
  20005.  
  20006.             if ($this->_compress_type == 'gz')
  20007.                 $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
  20008.             elseif ($this->_compress_type == 'bz2')
  20009.                 $v_temp_tar = @bzopen($this->_tarname.".tmp", "rb");
  20010.                 
  20011.             if ($v_temp_tar == 0) {
  20012.                 $this->_error('Unable to open file \''.$this->_tarname
  20013.                               .'.tmp\' in binary read mode');
  20014.                 @rename($this->_tarname.".tmp", $this->_tarname);
  20015.                 return false;
  20016.             }
  20017.  
  20018.             if (!$this->_openWrite()) {
  20019.                 @rename($this->_tarname.".tmp", $this->_tarname);
  20020.                 return false;
  20021.             }
  20022.  
  20023.             if ($this->_compress_type == 'gz') {
  20024.                 $v_buffer = @gzread($v_temp_tar, 512);
  20025.  
  20026.                 // ----- Read the following blocks but not the last one
  20027.                 if (!@gzeof($v_temp_tar)) {
  20028.                     do{
  20029.                         $v_binary_data = pack("a512", $v_buffer);
  20030.                         $this->_writeBlock($v_binary_data);
  20031.                         $v_buffer = @gzread($v_temp_tar, 512);
  20032.  
  20033.                     } while (!@gzeof($v_temp_tar));
  20034.                 }
  20035.  
  20036.                 @gzclose($v_temp_tar);
  20037.             }
  20038.             elseif ($this->_compress_type == 'bz2') {
  20039.                 $v_buffered_lines   = array();
  20040.                 $v_buffered_lines[] = @bzread($v_temp_tar, 512);
  20041.  
  20042.                 // ----- Read the following blocks but not the last one
  20043.                 while (strlen($v_buffered_lines[]
  20044.                               = @bzread($v_temp_tar, 512)) > 0) {
  20045.                     $v_binary_data = pack("a512",
  20046.                                           array_shift($v_buffered_lines));
  20047.                     $this->_writeBlock($v_binary_data);
  20048.                 }
  20049.  
  20050.                 @bzclose($v_temp_tar);
  20051.             }
  20052.  
  20053.             if (!@unlink($this->_tarname.".tmp")) {
  20054.                 $this->_error('Error while deleting temporary file \''
  20055.                               .$this->_tarname.'.tmp\'');
  20056.             }
  20057.  
  20058.         } else {
  20059.             // ----- For not compressed tar, just add files before the last
  20060.             //       512 bytes block
  20061.             if (!$this->_openReadWrite())
  20062.                return false;
  20063.  
  20064.             clearstatcache();
  20065.             $v_size = filesize($this->_tarname);
  20066.             fseek($this->_file, $v_size-512);
  20067.         }
  20068.  
  20069.         return true;
  20070.     }
  20071.     // }}}
  20072.  
  20073.     // {{{ _append()
  20074.     function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
  20075.     {
  20076.         if (!$this->_openAppend())
  20077.             return false;
  20078.             
  20079.         if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
  20080.            $this->_writeFooter();
  20081.  
  20082.         $this->_close();
  20083.  
  20084.         return true;
  20085.     }
  20086.     // }}}
  20087.  
  20088.     // {{{ _dirCheck()
  20089.  
  20090.     /**
  20091.      * Check if a directory exists and create it (including parent
  20092.      * dirs) if not.
  20093.      *
  20094.      * @param string $p_dir directory to check
  20095.      *
  20096.      * @return bool TRUE if the directory exists or was created
  20097.      */
  20098.     function _dirCheck($p_dir)
  20099.     {
  20100.         if ((@is_dir($p_dir)) || ($p_dir == ''))
  20101.             return true;
  20102.  
  20103.         $p_parent_dir = dirname($p_dir);
  20104.  
  20105.         if (($p_parent_dir != $p_dir) &&
  20106.             ($p_parent_dir != '') &&
  20107.             (!$this->_dirCheck($p_parent_dir)))
  20108.              return false;
  20109.  
  20110.         if (!@mkdir($p_dir, 0777)) {
  20111.             $this->_error("Unable to create directory '$p_dir'");
  20112.             return false;
  20113.         }
  20114.  
  20115.         return true;
  20116.     }
  20117.  
  20118.     // }}}
  20119.  
  20120.     // {{{ _pathReduction()
  20121.  
  20122.     /**
  20123.      * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", 
  20124.      * rand emove double slashes.
  20125.      *
  20126.      * @param string $p_dir path to reduce
  20127.      *
  20128.      * @return string reduced path
  20129.      *
  20130.      * @access private
  20131.      *
  20132.      */
  20133.     function _pathReduction($p_dir)
  20134.     {
  20135.         $v_result = '';
  20136.  
  20137.         // ----- Look for not empty path
  20138.         if ($p_dir != '') {
  20139.             // ----- Explode path by directory names
  20140.             $v_list = explode('/', $p_dir);
  20141.  
  20142.             // ----- Study directories from last to first
  20143.             for ($i=sizeof($v_list)-1; $i>=0; $i--) {
  20144.                 // ----- Look for current path
  20145.                 if ($v_list[$i] == ".") {
  20146.                     // ----- Ignore this directory
  20147.                     // Should be the first $i=0, but no check is done
  20148.                 }
  20149.                 else if ($v_list[$i] == "..") {
  20150.                     // ----- Ignore it and ignore the $i-1
  20151.                     $i--;
  20152.                 }
  20153.                 else if (   ($v_list[$i] == '')
  20154.                          && ($i!=(sizeof($v_list)-1))
  20155.                          && ($i!=0)) {
  20156.                     // ----- Ignore only the double '//' in path,
  20157.                     // but not the first and last /
  20158.                 } else {
  20159.                     $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?'/'
  20160.                                 .$v_result:'');
  20161.                 }
  20162.             }
  20163.         }
  20164.         $v_result = strtr($v_result, '\\', '/');
  20165.         return $v_result;
  20166.     }
  20167.  
  20168.     // }}}
  20169.  
  20170.     // {{{ _translateWinPath()
  20171.     function _translateWinPath($p_path, $p_remove_disk_letter=true)
  20172.     {
  20173.       if (OS_WINDOWS) {
  20174.           // ----- Look for potential disk letter
  20175.           if (   ($p_remove_disk_letter)
  20176.               && (($v_position = strpos($p_path, ':')) != false)) {
  20177.               $p_path = substr($p_path, $v_position+1);
  20178.           }
  20179.           // ----- Change potential windows directory separator
  20180.           if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) {
  20181.               $p_path = strtr($p_path, '\\', '/');
  20182.           }
  20183.       }
  20184.       return $p_path;
  20185.     }
  20186.     // }}}
  20187.  
  20188. }
  20189. ?>
  20190. Archive_Tar-1.3.1/docs/Archive_Tar.txt100666      0      0       44610 10166453403  12646 Documentation for class Archive_Tar
  20191. ===================================
  20192. Last update : 2001-08-15
  20193.  
  20194.  
  20195.  
  20196. Overview :
  20197. ----------
  20198.  
  20199.   The Archive_Tar class helps in creating and managing GNU TAR format
  20200.   files compressed by GNU ZIP or not. 
  20201.   The class offers basic functions like creating an archive, adding
  20202.   files in the archive, extracting files from the archive and listing
  20203.   the archive content. 
  20204.   It also provide advanced functions that allow the adding and
  20205.   extraction of files with path manipulation. 
  20206.  
  20207.  
  20208. Sample :
  20209. --------
  20210.  
  20211.   // ----- Creating the object (uncompressed archive)
  20212.   $tar_object = new Archive_Tar("tarname.tar");
  20213.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);
  20214.  
  20215.   // ----- Creating the archive
  20216.   $v_list[0]="file.txt";
  20217.   $v_list[1]="data/";
  20218.   $v_list[2]="file.log";
  20219.   $tar_object->create($v_list);
  20220.  
  20221.   // ----- Adding files
  20222.   $v_list[0]="dev/file.txt";
  20223.   $v_list[1]="dev/data/";
  20224.   $v_list[2]="log/file.log";
  20225.   $tar_object->add($v_list);
  20226.  
  20227.   // ----- Adding more files
  20228.   $tar_object->add("release/newfile.log release/readme.txt");
  20229.  
  20230.   // ----- Listing the content
  20231.   if (($v_list  =  $tar_object->listContent()) != 0)
  20232.     for ($i=0; $i<sizeof($v_list); $i++)
  20233.     {
  20234.       echo "Filename :'".$v_list[$i][filename]."'<br>";
  20235.       echo " .size :'".$v_list[$i][size]."'<br>";
  20236.       echo " .mtime :'".$v_list[$i][mtime]."' (".date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")<br>";
  20237.       echo " .mode :'".$v_list[$i][mode]."'<br>";
  20238.       echo " .uid :'".$v_list[$i][uid]."'<br>";
  20239.       echo " .gid :'".$v_list[$i][gid]."'<br>";
  20240.       echo " .typeflag :'".$v_list[$i][typeflag]."'<br>";
  20241.     }
  20242.  
  20243.   // ----- Extracting the archive in directory "install"
  20244.   $tar_object->extract("install");
  20245.  
  20246.  
  20247. Public arguments :
  20248. ------------------
  20249.  
  20250. None
  20251.  
  20252.  
  20253. Public Methods :
  20254. ----------------
  20255.  
  20256. Method : Archive_Tar($p_tarname, $compress = null)
  20257. Description :
  20258.   Archive_Tar Class constructor. This flavour of the constructor only
  20259.   declare a new Archive_Tar object, identifying it by the name of the
  20260.   tar file.
  20261.   If the compress argument is set the tar will be read or created as a
  20262.   gzip or bz2 compressed TAR file. 
  20263. Arguments :
  20264.   $p_tarname : A valid filename for the tar archive file.
  20265.   $p_compress : can be null, 'gz' or 'bz2'. For
  20266.                 compatibility reason it can also be true. This
  20267.                 parameter indicates if gzip or bz2 compression
  20268.                 is required. 
  20269. Return value :
  20270.   The Archive_Tar object.
  20271. Sample :
  20272.   $tar_object = new Archive_Tar("tarname.tar");
  20273.   $tar_object_compressed = new Archive_Tar("tarname.tgz", true);
  20274. How it works :
  20275.   Initialize the object.
  20276.  
  20277. Method : create($p_filelist)
  20278. Description :
  20279.   This method creates the archive file and add the files / directories
  20280.   that are listed in $p_filelist. 
  20281.   If the file already exists and is writable, it is replaced by the
  20282.   new tar. It is a create and not an add. If the file exists and is
  20283.   read-only or is a directory it is not replaced. The method return
  20284.   false and a PEAR error text. 
  20285.   The $p_filelist parameter can be an array of string, each string
  20286.   representing a filename or a directory name with their path if
  20287.   needed. It can also be a single string with names separated by a
  20288.   single blank. 
  20289.   See also createModify() method for more details.
  20290. Arguments :
  20291.   $p_filelist : An array of filenames and directory names, or a single
  20292.   string with names separated by a single blank space. 
  20293. Return value :
  20294.   true on success, false on error.
  20295. Sample 1 :
  20296.   $tar_object = new Archive_Tar("tarname.tar");
  20297.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  20298.   $v_list[0]="file.txt";
  20299.   $v_list[1]="data/"; (Optional '/' at the end)
  20300.   $v_list[2]="file.log";
  20301.   $tar_object->create($v_list);
  20302. Sample 2 :
  20303.   $tar_object = new Archive_Tar("tarname.tar");
  20304.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  20305.   $tar_object->create("file.txt data/ file.log");
  20306. How it works :
  20307.   Just calling the createModify() method with the right parameters.
  20308.  
  20309. Method : createModify($p_filelist, $p_add_dir, $p_remove_dir = "")
  20310. Description :
  20311.   This method creates the archive file and add the files / directories
  20312.   that are listed in $p_filelist. 
  20313.   If the file already exists and is writable, it is replaced by the
  20314.   new tar. It is a create and not an add. If the file exists and is
  20315.   read-only or is a directory it is not replaced. The method return
  20316.   false and a PEAR error text. 
  20317.   The $p_filelist parameter can be an array of string, each string
  20318.   representing a filename or a directory name with their path if
  20319.   needed. It can also be a single string with names separated by a
  20320.   single blank. 
  20321.   The path indicated in $p_remove_dir will be removed from the
  20322.   memorized path of each file / directory listed when this path
  20323.   exists. By default nothing is removed (empty path "") 
  20324.   The path indicated in $p_add_dir will be added at the beginning of
  20325.   the memorized path of each file / directory listed. However it can
  20326.   be set to empty "". The adding of a path is done after the removing
  20327.   of path. 
  20328.   The path add/remove ability enables the user to prepare an archive
  20329.   for extraction in a different path than the origin files are. 
  20330.   See also addModify() method for file adding properties.
  20331. Arguments :
  20332.   $p_filelist : An array of filenames and directory names, or a single
  20333.                 string with names separated by a single blank space.
  20334.   $p_add_dir : A string which contains a path to be added to the
  20335.                memorized path of each element in the list. 
  20336.   $p_remove_dir : A string which contains a path to be removed from
  20337.                   the memorized path of each element in the list, when
  20338.           relevant.
  20339. Return value :
  20340.   true on success, false on error.
  20341. Sample 1 :
  20342.   $tar_object = new Archive_Tar("tarname.tar");
  20343.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  20344.   $v_list[0]="file.txt";
  20345.   $v_list[1]="data/"; (Optional '/' at the end)
  20346.   $v_list[2]="file.log";
  20347.   $tar_object->createModify($v_list, "install");
  20348.   // files are stored in the archive as :
  20349.   //   install/file.txt
  20350.   //   install/data
  20351.   //   install/data/file1.txt
  20352.   //   install/data/... all the files and sub-dirs of data/
  20353.   //   install/file.log
  20354. Sample 2 :
  20355.   $tar_object = new Archive_Tar("tarname.tar");
  20356.   $tar_object->setErrorHandling(PEAR_ERROR_PRINT);  // Optional error handling
  20357.   $v_list[0]="dev/file.txt";
  20358.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  20359.   $v_list[2]="log/file.log";
  20360.   $tar_object->createModify($v_list, "install", "dev");
  20361.   // files are stored in the archive as :
  20362.   //   install/file.txt
  20363.   //   install/data
  20364.   //   install/data/file1.txt
  20365.   //   install/data/... all the files and sub-dirs of data/
  20366.   //   install/log/file.log
  20367. How it works :
  20368.   Open the file in write mode (erasing the existing one if one),
  20369.   call the _addList() method for adding the files in an empty archive,
  20370.   add the tar footer (512 bytes block), close the tar file.
  20371.  
  20372.  
  20373. Method : addModify($p_filelist, $p_add_dir, $p_remove_dir="")
  20374. Description :
  20375.   This method add the files / directories listed in $p_filelist at the
  20376.   end of the existing archive. If the archive does not yet exists it
  20377.   is created.
  20378.   The $p_filelist parameter can be an array of string, each string
  20379.   representing a filename or a directory name with their path if
  20380.   needed. It can also be a single string with names separated by a
  20381.   single blank. 
  20382.   The path indicated in $p_remove_dir will be removed from the
  20383.   memorized path of each file / directory listed when this path
  20384.   exists. By default nothing is removed (empty path "") 
  20385.   The path indicated in $p_add_dir will be added at the beginning of
  20386.   the memorized path of each file / directory listed. However it can
  20387.   be set to empty "". The adding of a path is done after the removing
  20388.   of path. 
  20389.   The path add/remove ability enables the user to prepare an archive
  20390.   for extraction in a different path than the origin files are. 
  20391.   If a file/dir is already in the archive it will only be added at the
  20392.   end of the archive. There is no update of the existing archived
  20393.   file/dir. However while extracting the archive, the last file will
  20394.   replace the first one. This results in a none optimization of the
  20395.   archive size. 
  20396.   If a file/dir does not exist the file/dir is ignored. However an
  20397.   error text is send to PEAR error. 
  20398.   If a file/dir is not readable the file/dir is ignored. However an
  20399.   error text is send to PEAR error. 
  20400.   If the resulting filename/dirname (after the add/remove option or
  20401.   not) string is greater than 99 char, the file/dir is
  20402.   ignored. However an error text is send to PEAR error. 
  20403. Arguments :
  20404.   $p_filelist : An array of filenames and directory names, or a single
  20405.                 string with names separated by a single blank space. 
  20406.   $p_add_dir : A string which contains a path to be added to the
  20407.                memorized path of each element in the list. 
  20408.   $p_remove_dir : A string which contains a path to be removed from
  20409.                   the memorized path of each element in the list, when
  20410.           relevant.
  20411. Return value :
  20412.   true on success, false on error.
  20413. Sample 1 :
  20414.   $tar_object = new Archive_Tar("tarname.tar");
  20415.   [...]
  20416.   $v_list[0]="dev/file.txt";
  20417.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  20418.   $v_list[2]="log/file.log";
  20419.   $tar_object->addModify($v_list, "install");
  20420.   // files are stored in the archive as :
  20421.   //   install/file.txt
  20422.   //   install/data
  20423.   //   install/data/file1.txt
  20424.   //   install/data/... all the files and sub-dirs of data/
  20425.   //   install/file.log
  20426. Sample 2 :
  20427.   $tar_object = new Archive_Tar("tarname.tar");
  20428.   [...]
  20429.   $v_list[0]="dev/file.txt";
  20430.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  20431.   $v_list[2]="log/file.log";
  20432.   $tar_object->addModify($v_list, "install", "dev");
  20433.   // files are stored in the archive as :
  20434.   //   install/file.txt
  20435.   //   install/data
  20436.   //   install/data/file1.txt
  20437.   //   install/data/... all the files and sub-dirs of data/
  20438.   //   install/log/file.log
  20439. How it works :
  20440.   If the archive does not exists it create it and add the files.
  20441.   If the archive does exists and is not compressed, it open it, jump
  20442.   before the last empty 512 bytes block (tar footer) and add the files
  20443.   at this point.
  20444.   If the archive does exists and is compressed, a temporary copy file
  20445.   is created. This temporary file is then 'gzip' read block by block
  20446.   until the last empty block. The new files are then added in the
  20447.   compressed file.
  20448.   The adding of files is done by going through the file/dir list,
  20449.   adding files per files, in a recursive way through the
  20450.   directory. Each time a path need to be added/removed it is done
  20451.   before writing the file header in the archive.
  20452.  
  20453. Method : add($p_filelist)
  20454. Description :
  20455.   This method add the files / directories listed in $p_filelist at the
  20456.   end of the existing archive. If the archive does not yet exists it
  20457.   is created. 
  20458.   The $p_filelist parameter can be an array of string, each string
  20459.   representing a filename or a directory name with their path if
  20460.   needed. It can also be a single string with names separated by a
  20461.   single blank. 
  20462.   See addModify() method for details and limitations.
  20463. Arguments :
  20464.   $p_filelist : An array of filenames and directory names, or a single
  20465.   string with names separated by a single blank space. 
  20466. Return value :
  20467.   true on success, false on error.
  20468. Sample 1 :
  20469.   $tar_object = new Archive_Tar("tarname.tar");
  20470.   [...]
  20471.   $v_list[0]="dev/file.txt";
  20472.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  20473.   $v_list[2]="log/file.log";
  20474.   $tar_object->add($v_list);
  20475. Sample 2 :
  20476.   $tar_object = new Archive_Tar("tarname.tgz", true);
  20477.   [...]
  20478.   $v_list[0]="dev/file.txt";
  20479.   $v_list[1]="dev/data/"; (Optional '/' at the end)
  20480.   $v_list[2]="log/file.log";
  20481.   $tar_object->add($v_list);
  20482. How it works :
  20483.   Simply call the addModify() method with the right parameters.
  20484.  
  20485. Method : addString($p_filename, $p_string)
  20486. Description :
  20487.   This method add a single string as a file at the
  20488.   end of the existing archive. If the archive does not yet exists it
  20489.   is created.
  20490. Arguments :
  20491.   $p_filename : A string which contains the full filename path
  20492.                 that will be associated with the string.
  20493.   $p_string :   The content of the file added in the archive.
  20494. Return value :
  20495.   true on success, false on error.
  20496. Sample 1 :
  20497.   $v_archive = & new Archive_Tar($p_filename);
  20498.   $v_archive->setErrorHandling(PEAR_ERROR_PRINT);
  20499.   $v_result = $v_archive->addString('data/test.txt', 'This is the text of the string');
  20500.  
  20501.  
  20502. Method : extract($p_path = "")
  20503. Description :
  20504.   This method extract all the content of the archive in the directory
  20505.   indicated by $p_path.If $p_path is optional, if not set the archive
  20506.   is extracted in the current directory. 
  20507.   While extracting a file, if the directory path does not exists it is
  20508.   created. 
  20509.   See extractModify() for details and limitations.
  20510. Arguments :
  20511.   $p_path : Optional path where the files/dir need to by extracted.
  20512. Return value :
  20513.   true on success, false on error.
  20514. Sample :
  20515.   $tar_object = new Archive_Tar("tarname.tar");
  20516.   $tar_object->extract();
  20517. How it works :
  20518.   Simply call the extractModify() method with appropriate parameters.
  20519.  
  20520. Method : extractModify($p_path, $p_remove_path)
  20521. Description :
  20522.   This method extract all the content of the archive in the directory
  20523.   indicated by $p_path. When relevant the memorized path of the
  20524.   files/dir can be modified by removing the $p_remove_path path at the
  20525.   beginning of the file/dir path. 
  20526.   While extracting a file, if the directory path does not exists it is
  20527.   created. 
  20528.   While extracting a file, if the file already exists it is replaced
  20529.   without looking for last modification date. 
  20530.   While extracting a file, if the file already exists and is write
  20531.   protected, the extraction is aborted. 
  20532.   While extracting a file, if a directory with the same name already
  20533.   exists, the extraction is aborted. 
  20534.   While extracting a directory, if a file with the same name already
  20535.   exists, the extraction is aborted. 
  20536.   While extracting a file/directory if the destination directory exist
  20537.   and is write protected, or does not exist but can not be created,
  20538.   the extraction is aborted. 
  20539.   If after extraction an extracted file does not show the correct
  20540.   stored file size, the extraction is aborted. 
  20541.   When the extraction is aborted, a PEAR error text is set and false
  20542.   is returned. However the result can be a partial extraction that may
  20543.   need to be manually cleaned. 
  20544. Arguments :
  20545.   $p_path : The path of the directory where the files/dir need to by
  20546.             extracted. 
  20547.   $p_remove_path : Part of the memorized path that can be removed if
  20548.                    present at the beginning of the file/dir path. 
  20549. Return value :
  20550.   true on success, false on error.
  20551. Sample :
  20552.   // Imagine tarname.tar with files :
  20553.   //   dev/data/file.txt
  20554.   //   dev/data/log.txt
  20555.   //   readme.txt
  20556.   $tar_object = new Archive_Tar("tarname.tar");
  20557.   $tar_object->extractModify("install", "dev");
  20558.   // Files will be extracted there :
  20559.   //   install/data/file.txt
  20560.   //   install/data/log.txt
  20561.   //   install/readme.txt
  20562. How it works :
  20563.   Open the archive and call a more generic function that can extract
  20564.   only a part of the archive or all the archive. 
  20565.   See extractList() method for more details.
  20566.  
  20567. Method : extractInString($p_filename)
  20568. Description :
  20569.   This method extract from the archive one file identified by $p_filename.
  20570.   The return value is a string with the file content, or NULL on error. 
  20571. Arguments :
  20572.   $p_filename : The path of the file to extract in a string. 
  20573. Return value :
  20574.   a string with the file content or NULL.
  20575. Sample :
  20576.   // Imagine tarname.tar with files :
  20577.   //   dev/data/file.txt
  20578.   //   dev/data/log.txt
  20579.   //   dev/readme.txt
  20580.   $v_archive = & new Archive_Tar('tarname.tar');
  20581.   $v_archive->setErrorHandling(PEAR_ERROR_PRINT);
  20582.   $v_string = $v_archive->extractInString('dev/readme.txt');
  20583.   echo $v_string;
  20584.  
  20585. Method : listContent()
  20586. Description :
  20587.   This method returns an array of arrays that describe each
  20588.   file/directory present in the archive. 
  20589.   The array is not sorted, so it show the position of the file in the
  20590.   archive. 
  20591.   The file informations are :
  20592.     $file[filename] : Name and path of the file/dir.
  20593.     $file[mode] : File permissions (result of fileperms())
  20594.     $file[uid] : user id
  20595.     $file[gid] : group id
  20596.     $file[size] : filesize
  20597.     $file[mtime] : Last modification time (result of filemtime())
  20598.     $file[typeflag] : "" for file, "5" for directory
  20599. Arguments :
  20600. Return value :
  20601.   An array of arrays or 0 on error.
  20602. Sample :
  20603.   $tar_object = new Archive_Tar("tarname.tar");
  20604.   if (($v_list  =  $tar_object->listContent()) != 0)
  20605.     for ($i=0; $i<sizeof($v_list); $i++)
  20606.     {
  20607.       echo "Filename :'".$v_list[$i][filename]."'<br>";
  20608.       echo " .size :'".$v_list[$i][size]."'<br>";
  20609.       echo " .mtime :'".$v_list[$i][mtime]."' (".
  20610.            date("l dS of F Y h:i:s A", $v_list[$i][mtime]).")<br>";
  20611.       echo " .mode :'".$v_list[$i][mode]."'<br>";
  20612.       echo " .uid :'".$v_list[$i][uid]."'<br>";
  20613.       echo " .gid :'".$v_list[$i][gid]."'<br>";
  20614.       echo " .typeflag :'".$v_list[$i][typeflag]."'<br>";
  20615.     }
  20616. How it works :
  20617.   Call the same function as an extract however with a flag to only go
  20618.   through the archive without extracting the files. 
  20619.  
  20620. Method : extractList($p_filelist, $p_path = "", $p_remove_path = "")
  20621. Description :
  20622.   This method extract from the archive only the files indicated in the
  20623.   $p_filelist. These files are extracted in the current directory or
  20624.   in the directory indicated by the optional $p_path parameter. 
  20625.   If indicated the $p_remove_path can be used in the same way as it is
  20626.   used in extractModify() method. 
  20627. Arguments :
  20628.   $p_filelist : An array of filenames and directory names, or a single
  20629.                 string with names separated by a single blank space. 
  20630.   $p_path : The path of the directory where the files/dir need to by
  20631.             extracted. 
  20632.   $p_remove_path : Part of the memorized path that can be removed if
  20633.                    present at the beginning of the file/dir path. 
  20634. Return value :
  20635.   true on success, false on error.
  20636. Sample :
  20637.   // Imagine tarname.tar with files :
  20638.   //   dev/data/file.txt
  20639.   //   dev/data/log.txt
  20640.   //   readme.txt
  20641.   $tar_object = new Archive_Tar("tarname.tar");
  20642.   $tar_object->extractList("dev/data/file.txt readme.txt", "install",
  20643.                            "dev");
  20644.   // Files will be extracted there :
  20645.   //   install/data/file.txt
  20646.   //   install/readme.txt
  20647. How it works :
  20648.   Go through the archive and extract only the files present in the
  20649.   list. 
  20650.  
  20651. package.xml100644      0      0        4022  7766142160   6212 <?xml version="1.0" encoding="ISO-8859-1" ?>
  20652. <!DOCTYPE package SYSTEM "http://pear.php.net/dtd/package-1.0">
  20653. <package version="1.0">
  20654.   <name>Console_Getopt</name>
  20655.   <summary>Command-line option parser</summary>
  20656.   <description>This is a PHP implementation of "getopt" supporting both
  20657. short and long options.</description>
  20658.   <maintainers>
  20659.     <maintainer>
  20660.       <user>andrei</user>
  20661.       <name>Andrei Zmievski</name>
  20662.       <email>andrei@php.net</email>
  20663.       <role>lead</role>
  20664.     </maintainer>
  20665.     <maintainer>
  20666.       <user>ssb</user>
  20667.       <name>Stig Bakken</name>
  20668.       <email>stig@php.net</email>
  20669.       <role>developer</role>
  20670.     </maintainer>
  20671.   </maintainers>
  20672.   <release>
  20673.     <version>1.2</version>
  20674.     <date>2003-12-11</date>
  20675.     <license>PHP License</license>
  20676.     <state>stable</state>
  20677.     <notes>Fix to preserve BC with 1.0 and allow correct behaviour for new users</notes>
  20678.     <provides type="class" name="Console_Getopt" />
  20679.     <provides type="function" name="Console_Getopt::getopt2" />
  20680.     <provides type="function" name="Console_Getopt::getopt" />
  20681.     <provides type="function" name="Console_Getopt::doGetopt" />
  20682.     <provides type="function" name="Console_Getopt::readPHPArgv" />
  20683.     <filelist>
  20684.       <file role="php" md5sum="add0781a1cae0b3daf5e8521b8a954cc" name="Console/Getopt.php"/>
  20685.     </filelist>
  20686.   </release>
  20687.   <changelog>
  20688.     <release>
  20689.       <version>1.0</version>
  20690.       <date>2002-09-13</date>
  20691.       <state>stable</state>
  20692.       <notes>Stable release
  20693. </notes>
  20694.     </release>
  20695.     <release>
  20696.       <version>0.11</version>
  20697.       <date>2002-05-26</date>
  20698.       <state>beta</state>
  20699.       <notes>POSIX getopt compatibility fix: treat first element of args
  20700.        array as command name
  20701.      
  20702. </notes>
  20703.     </release>
  20704.     <release>
  20705.       <version>0.10</version>
  20706.       <date>2002-05-12</date>
  20707.       <state>beta</state>
  20708.       <notes>Packaging fix
  20709. </notes>
  20710.     </release>
  20711.     <release>
  20712.       <version>0.9</version>
  20713.       <date>2002-05-12</date>
  20714.       <state>beta</state>
  20715.       <notes>Initial release
  20716. </notes>
  20717.     </release>
  20718.   </changelog>
  20719. </package>
  20720. Console_Getopt-1.2/Console/Getopt.php100644    764    764       22500  7766141652  13064 <?php
  20721. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  20722. // +----------------------------------------------------------------------+
  20723. // | PHP Version 4                                                        |
  20724. // +----------------------------------------------------------------------+
  20725. // | Copyright (c) 1997-2003 The PHP Group                                |
  20726. // +----------------------------------------------------------------------+
  20727. // | This source file is subject to version 3.0 of the PHP license,       |
  20728. // | that is bundled with this package in the file LICENSE, and is        |
  20729. // | available through the world-wide-web at the following url:           |
  20730. // | http://www.php.net/license/3_0.txt.                                  |
  20731. // | If you did not receive a copy of the PHP license and are unable to   |
  20732. // | obtain it through the world-wide-web, please send a note to          |
  20733. // | license@php.net so we can mail you a copy immediately.               |
  20734. // +----------------------------------------------------------------------+
  20735. // | Author: Andrei Zmievski <andrei@php.net>                             |
  20736. // +----------------------------------------------------------------------+
  20737. //
  20738. // $Id: Getopt.php,v 1.21.4.7 2003/12/05 21:57:01 andrei Exp $
  20739.  
  20740. require_once 'PEAR.php';
  20741.  
  20742. /**
  20743.  * Command-line options parsing class.
  20744.  *
  20745.  * @author Andrei Zmievski <andrei@php.net>
  20746.  *
  20747.  */
  20748. class Console_Getopt {
  20749.     /**
  20750.      * Parses the command-line options.
  20751.      *
  20752.      * The first parameter to this function should be the list of command-line
  20753.      * arguments without the leading reference to the running program.
  20754.      *
  20755.      * The second parameter is a string of allowed short options. Each of the
  20756.      * option letters can be followed by a colon ':' to specify that the option
  20757.      * requires an argument, or a double colon '::' to specify that the option
  20758.      * takes an optional argument.
  20759.      *
  20760.      * The third argument is an optional array of allowed long options. The
  20761.      * leading '--' should not be included in the option name. Options that
  20762.      * require an argument should be followed by '=', and options that take an
  20763.      * option argument should be followed by '=='.
  20764.      *
  20765.      * The return value is an array of two elements: the list of parsed
  20766.      * options and the list of non-option command-line arguments. Each entry in
  20767.      * the list of parsed options is a pair of elements - the first one
  20768.      * specifies the option, and the second one specifies the option argument,
  20769.      * if there was one.
  20770.      *
  20771.      * Long and short options can be mixed.
  20772.      *
  20773.      * Most of the semantics of this function are based on GNU getopt_long().
  20774.      *
  20775.      * @param array  $args           an array of command-line arguments
  20776.      * @param string $short_options  specifies the list of allowed short options
  20777.      * @param array  $long_options   specifies the list of allowed long options
  20778.      *
  20779.      * @return array two-element array containing the list of parsed options and
  20780.      * the non-option arguments
  20781.      *
  20782.      * @access public
  20783.      *
  20784.      */
  20785.     function getopt2($args, $short_options, $long_options = null)
  20786.     {
  20787.         return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
  20788.     }
  20789.  
  20790.     /**
  20791.      * This function expects $args to start with the script name (POSIX-style).
  20792.      * Preserved for backwards compatibility.
  20793.      * @see getopt2()
  20794.      */    
  20795.     function getopt($args, $short_options, $long_options = null)
  20796.     {
  20797.         return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
  20798.     }
  20799.  
  20800.     /**
  20801.      * The actual implementation of the argument parsing code.
  20802.      */
  20803.     function doGetopt($version, $args, $short_options, $long_options = null)
  20804.     {
  20805.         // in case you pass directly readPHPArgv() as the first arg
  20806.         if (PEAR::isError($args)) {
  20807.             return $args;
  20808.         }
  20809.         if (empty($args)) {
  20810.             return array(array(), array());
  20811.         }
  20812.         $opts     = array();
  20813.         $non_opts = array();
  20814.  
  20815.         settype($args, 'array');
  20816.  
  20817.         if ($long_options) {
  20818.             sort($long_options);
  20819.         }
  20820.  
  20821.         /*
  20822.          * Preserve backwards compatibility with callers that relied on
  20823.          * erroneous POSIX fix.
  20824.          */
  20825.         if ($version < 2) {
  20826.             if (isset($args[0]{0}) && $args[0]{0} != '-') {
  20827.                 array_shift($args);
  20828.             }
  20829.         }
  20830.  
  20831.         reset($args);
  20832.         while (list($i, $arg) = each($args)) {
  20833.  
  20834.             /* The special element '--' means explicit end of
  20835.                options. Treat the rest of the arguments as non-options
  20836.                and end the loop. */
  20837.             if ($arg == '--') {
  20838.                 $non_opts = array_merge($non_opts, array_slice($args, $i + 1));
  20839.                 break;
  20840.             }
  20841.  
  20842.             if ($arg{0} != '-' || (strlen($arg) > 1 && $arg{1} == '-' && !$long_options)) {
  20843.                 $non_opts = array_merge($non_opts, array_slice($args, $i));
  20844.                 break;
  20845.             } elseif (strlen($arg) > 1 && $arg{1} == '-') {
  20846.                 $error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
  20847.                 if (PEAR::isError($error))
  20848.                     return $error;
  20849.             } else {
  20850.                 $error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
  20851.                 if (PEAR::isError($error))
  20852.                     return $error;
  20853.             }
  20854.         }
  20855.  
  20856.         return array($opts, $non_opts);
  20857.     }
  20858.  
  20859.     /**
  20860.      * @access private
  20861.      *
  20862.      */
  20863.     function _parseShortOption($arg, $short_options, &$opts, &$args)
  20864.     {
  20865.         for ($i = 0; $i < strlen($arg); $i++) {
  20866.             $opt = $arg{$i};
  20867.             $opt_arg = null;
  20868.  
  20869.             /* Try to find the short option in the specifier string. */
  20870.             if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
  20871.             {
  20872.                 return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
  20873.             }
  20874.  
  20875.             if (strlen($spec) > 1 && $spec{1} == ':') {
  20876.                 if (strlen($spec) > 2 && $spec{2} == ':') {
  20877.                     if ($i + 1 < strlen($arg)) {
  20878.                         /* Option takes an optional argument. Use the remainder of
  20879.                            the arg string if there is anything left. */
  20880.                         $opts[] = array($opt, substr($arg, $i + 1));
  20881.                         break;
  20882.                     }
  20883.                 } else {
  20884.                     /* Option requires an argument. Use the remainder of the arg
  20885.                        string if there is anything left. */
  20886.                     if ($i + 1 < strlen($arg)) {
  20887.                         $opts[] = array($opt,  substr($arg, $i + 1));
  20888.                         break;
  20889.                     } else if (list(, $opt_arg) = each($args))
  20890.                         /* Else use the next argument. */;
  20891.                     else
  20892.                         return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
  20893.                 }
  20894.             }
  20895.  
  20896.             $opts[] = array($opt, $opt_arg);
  20897.         }
  20898.     }
  20899.  
  20900.     /**
  20901.      * @access private
  20902.      *
  20903.      */
  20904.     function _parseLongOption($arg, $long_options, &$opts, &$args)
  20905.     {
  20906.         @list($opt, $opt_arg) = explode('=', $arg);
  20907.         $opt_len = strlen($opt);
  20908.  
  20909.         for ($i = 0; $i < count($long_options); $i++) {
  20910.             $long_opt  = $long_options[$i];
  20911.             $opt_start = substr($long_opt, 0, $opt_len);
  20912.  
  20913.             /* Option doesn't match. Go on to the next one. */
  20914.             if ($opt_start != $opt)
  20915.                 continue;
  20916.  
  20917.             $opt_rest  = substr($long_opt, $opt_len);
  20918.  
  20919.             /* Check that the options uniquely matches one of the allowed
  20920.                options. */
  20921.             if ($opt_rest != '' && $opt{0} != '=' &&
  20922.                 $i + 1 < count($long_options) &&
  20923.                 $opt == substr($long_options[$i+1], 0, $opt_len)) {
  20924.                 return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous");
  20925.             }
  20926.  
  20927.             if (substr($long_opt, -1) == '=') {
  20928.                 if (substr($long_opt, -2) != '==') {
  20929.                     /* Long option requires an argument.
  20930.                        Take the next argument if one wasn't specified. */;
  20931.                     if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
  20932.                         return PEAR::raiseError("Console_Getopt: option --$opt requires an argument");
  20933.                     }
  20934.                 }
  20935.             } else if ($opt_arg) {
  20936.                 return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
  20937.             }
  20938.  
  20939.             $opts[] = array('--' . $opt, $opt_arg);
  20940.             return;
  20941.         }
  20942.  
  20943.         return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
  20944.     }
  20945.  
  20946.     /**
  20947.     * Safely read the $argv PHP array across different PHP configurations.
  20948.     * Will take care on register_globals and register_argc_argv ini directives
  20949.     *
  20950.     * @access public
  20951.     * @return mixed the $argv PHP array or PEAR error if not registered
  20952.     */
  20953.     function readPHPArgv()
  20954.     {
  20955.         global $argv;
  20956.         if (!is_array($argv)) {
  20957.             if (!@is_array($_SERVER['argv'])) {
  20958.                 if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
  20959.                     return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
  20960.                 }
  20961.                 return $GLOBALS['HTTP_SERVER_VARS']['argv'];
  20962.             }
  20963.             return $_SERVER['argv'];
  20964.         }
  20965.         return $argv;
  20966.     }
  20967.  
  20968. }
  20969.  
  20970. ?>
  20971. package2.xml100644   1750   1750      110703 10470570063   6543 <?xml version="1.0" encoding="UTF-8"?>
  20972. <package packagerversion="1.4.11" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
  20973.  <name>PEAR</name>
  20974.  <channel>pear.php.net</channel>
  20975.  <summary>PEAR Base System</summary>
  20976.  <description>The PEAR package contains:
  20977.  * the PEAR installer, for creating, distributing
  20978.    and installing packages
  20979.  * the beta-quality PEAR_Exception PHP5 error handling mechanism
  20980.  * the beta-quality PEAR_ErrorStack advanced error handling mechanism
  20981.  * the PEAR_Error error handling mechanism
  20982.  * the OS_Guess class for retrieving info about the OS
  20983.    where PHP is running on
  20984.  * the System class for quick handling of common operations
  20985.    with files and directories
  20986.  * the PEAR base class
  20987.  
  20988.   New features in a nutshell:
  20989.   * full support for channels
  20990.   * pre-download dependency validation
  20991.   * new package.xml 2.0 format allows tremendous flexibility while maintaining BC
  20992.   * support for optional dependency groups and limited support for sub-packaging
  20993.   * robust dependency support
  20994.   * full dependency validation on uninstall
  20995.   * remote install for hosts with only ftp access - no more problems with
  20996.     restricted host installation
  20997.   * full support for mirroring
  20998.   * support for bundling several packages into a single tarball
  20999.   * support for static dependencies on a url-based package
  21000.   * support for custom file roles and installation tasks
  21001.  
  21002.   NOTE: users of PEAR_Frontend_Web/PEAR_Frontend_Gtk must upgrade their installations
  21003.   to the latest version, or PEAR will not upgrade properly</description>
  21004.  <lead>
  21005.   <name>Greg Beaver</name>
  21006.   <user>cellog</user>
  21007.   <email>cellog@php.net</email>
  21008.   <active>yes</active>
  21009.  </lead>
  21010.  <lead>
  21011.   <name>Pierre-Alain Joye</name>
  21012.   <user>pajoye</user>
  21013.   <email>pajoye@pearfr.org</email>
  21014.   <active>yes</active>
  21015.  </lead>
  21016.  <lead>
  21017.   <name>Stig Bakken</name>
  21018.   <user>ssb</user>
  21019.   <email>stig@php.net</email>
  21020.   <active>no</active>
  21021.  </lead>
  21022.  <lead>
  21023.   <name>Tomas V.V.Cox</name>
  21024.   <user>cox</user>
  21025.   <email>cox@idecnet.com</email>
  21026.   <active>no</active>
  21027.  </lead>
  21028.  <helper>
  21029.   <name>Tim Jackson</name>
  21030.   <user>timj</user>
  21031.   <email>timj@php.net</email>
  21032.   <active>yes</active>
  21033.  </helper>
  21034.  <helper>
  21035.   <name>Bertrand Gugger</name>
  21036.   <user>toggg</user>
  21037.   <email>toggg@php.net</email>
  21038.   <active>no</active>
  21039.  </helper>
  21040.  <helper>
  21041.   <name>Martin Jansen</name>
  21042.   <user>mj</user>
  21043.   <email>mj@php.net</email>
  21044.   <active>no</active>
  21045.  </helper>
  21046.  <date>2006-08-16</date>
  21047.  <time>12:15:15</time>
  21048.  <version>
  21049.   <release>1.4.11</release>
  21050.   <api>1.4.2</api>
  21051.  </version>
  21052.  <stability>
  21053.   <release>stable</release>
  21054.   <api>stable</api>
  21055.  </stability>
  21056.  <license uri="http://www.php.net/license">PHP License</license>
  21057.  <notes>minor bugfix release
  21058. * fix the conflicts detection for the web frontend (before 0.5.0)
  21059. * fix warnings in the list-all command</notes>
  21060.  <contents>
  21061.   <dir name="/">
  21062.    <file md5sum="b309a1eb31b2826cd1cec229fb352eb0" name="OS/Guess.php" role="php">
  21063.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21064.    </file>
  21065.    <file md5sum="28016a108b34962267f86ccc1d70d852" name="PEAR/ChannelFile/Parser.php" role="php">
  21066.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21067.    </file>
  21068.    <file md5sum="4a11a3c4bc2c2f338c183b332def156b" name="PEAR/Command/Auth.xml" role="php" />
  21069.    <file md5sum="20a596c843275e8607c0e1fdc7953e64" name="PEAR/Command/Auth.php" role="php">
  21070.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21071.    </file>
  21072.    <file md5sum="73602fd7f051eaf8d37452d0e3063bdb" name="PEAR/Command/Build.xml" role="php" />
  21073.    <file md5sum="bf340957761207ff4408b560cba982e1" name="PEAR/Command/Build.php" role="php">
  21074.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21075.    </file>
  21076.    <file md5sum="d5586c3708924122c9383738315f6539" name="PEAR/Command/Channels.xml" role="php" />
  21077.    <file md5sum="f68e6ae36ed4dd9e3b4cd2a8d67e1227" name="PEAR/Command/Channels.php" role="php">
  21078.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21079.    </file>
  21080.    <file md5sum="0033cb00b42b118df88c0daaacbfe1d3" name="PEAR/Command/Common.php" role="php">
  21081.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21082.    </file>
  21083.    <file md5sum="91f189cb9423b5e87ee0abc5ea1a2be3" name="PEAR/Command/Config.xml" role="php" />
  21084.    <file md5sum="12df978b3560fc1e846ecbd5e367240c" name="PEAR/Command/Config.php" role="php">
  21085.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21086.    </file>
  21087.    <file md5sum="516da3eb7ebbecfbfb4188408a1983b2" name="PEAR/Command/Install.xml" role="php" />
  21088.    <file md5sum="aa6ea8b7087130a518fcbb401f3369c6" name="PEAR/Command/Install.php" role="php">
  21089.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21090.    </file>
  21091.    <file md5sum="5cb62a04c0a268f4edd64a49a3895c92" name="PEAR/Command/Mirror.xml" role="php" />
  21092.    <file md5sum="d35b596f8c060eb666797cd2f0f61643" name="PEAR/Command/Mirror.php" role="php">
  21093.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21094.    </file>
  21095.    <file md5sum="bbf88f26cd10b1caa76d5eec474f093f" name="PEAR/Command/Package.xml" role="php" />
  21096.    <file md5sum="ed3d49a880913827d7c3a1beacb5531c" name="PEAR/Command/Package.php" role="php">
  21097.     <tasks:replace from="@DATA-DIR@" to="data_dir" type="pear-config" />
  21098.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21099.    </file>
  21100.    <file md5sum="35817866283227237796b32d32dac44d" name="PEAR/Command/Pickle.xml" role="php" />
  21101.    <file md5sum="dea2b4d9388a9511e59548c61f60251a" name="PEAR/Command/Pickle.php" role="php">
  21102.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21103.    </file>
  21104.    <file md5sum="e7fc652e4b5266bbac1c23140de01598" name="PEAR/Command/Registry.xml" role="php" />
  21105.    <file md5sum="2f8013f7a0c1e2f2ba7ca3113135015d" name="PEAR/Command/Registry.php" role="php">
  21106.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21107.    </file>
  21108.    <file md5sum="d57b54857aba5b6ff2fe528cbf522b00" name="PEAR/Command/Remote.xml" role="php" />
  21109.    <file md5sum="ad00e67d39dc0d15c5ed9cbd26992ec9" name="PEAR/Command/Remote.php" role="php">
  21110.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21111.    </file>
  21112.    <file md5sum="f5072ed4032dc28fac20f526f03520f8" name="PEAR/Command/Test.xml" role="php" />
  21113.    <file md5sum="a537a76b067ccdac893469fb95c1c9cc" name="PEAR/Command/Test.php" role="php">
  21114.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21115.    </file>
  21116.    <file md5sum="9643b5ff1188628499cbbd6050e9cbab" name="PEAR/Downloader/Package.php" role="php">
  21117.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  21118.    </file>
  21119.    <file md5sum="e0417ade6ffb4235c8f6fee2b9779a25" name="PEAR/Frontend/CLI.php" role="php">
  21120.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21121.    </file>
  21122.    <file md5sum="80ac44ab528facdffacc2f2183d351cf" name="PEAR/Installer/Role/Common.php" role="php">
  21123.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21124.    </file>
  21125.    <file md5sum="a102cceaf8e9348965a856e2b5ae4e35" name="PEAR/Installer/Role/Data.xml" role="php" />
  21126.    <file md5sum="594fe03ab037716e90f01036b238dac9" name="PEAR/Installer/Role/Data.php" role="php">
  21127.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21128.    </file>
  21129.    <file md5sum="5755c03e061dd14ab04a8662a860af13" name="PEAR/Installer/Role/Doc.xml" role="php" />
  21130.    <file md5sum="691537b382e6c38b1da2797ce38a0950" name="PEAR/Installer/Role/Doc.php" role="php">
  21131.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21132.    </file>
  21133.    <file md5sum="2752669b1ccf927c4c71db68ac046095" name="PEAR/Installer/Role/Ext.xml" role="php" />
  21134.    <file md5sum="0e3823a9702ca20530761c0f9b7cd678" name="PEAR/Installer/Role/Ext.php" role="php">
  21135.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21136.    </file>
  21137.    <file md5sum="8997db19129f121be2d5fffb92f4075a" name="PEAR/Installer/Role/Php.xml" role="php" />
  21138.    <file md5sum="99a73d79d2647c5b573c7e929d476fb7" name="PEAR/Installer/Role/Php.php" role="php">
  21139.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21140.    </file>
  21141.    <file md5sum="a146c5985d669938c633bfef60692db4" name="PEAR/Installer/Role/Script.xml" role="php" />
  21142.    <file md5sum="f9d6d3999088c48ce4638d938e7ab158" name="PEAR/Installer/Role/Script.php" role="php">
  21143.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21144.    </file>
  21145.    <file md5sum="ad0f719669cb90e76048394896c51136" name="PEAR/Installer/Role/Src.xml" role="php" />
  21146.    <file md5sum="70626b32b828aae617853372287098f2" name="PEAR/Installer/Role/Src.php" role="php">
  21147.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21148.    </file>
  21149.    <file md5sum="dc2f729ae9356540c91131b3b94caddf" name="PEAR/Installer/Role/Test.xml" role="php" />
  21150.    <file md5sum="7e5652e079b75f15b8ea1541fde125e6" name="PEAR/Installer/Role/Test.php" role="php">
  21151.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21152.    </file>
  21153.    <file md5sum="4640fe2a15a082b57361bf7522d3b0fa" name="PEAR/Installer/Role.php" role="php">
  21154.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21155.    </file>
  21156.    <file md5sum="786d5cb198bc0ff160c202519c20201e" name="PEAR/PackageFile/Generator/v1.php" role="php">
  21157.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  21158.    </file>
  21159.    <file md5sum="1c4afb91b1dd8f310f42b5f5531a0dea" name="PEAR/PackageFile/Generator/v2.php" role="php">
  21160.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  21161.    </file>
  21162.    <file md5sum="ea3c85eac9d81f6ac0d445219b882c8b" name="PEAR/PackageFile/Parser/v1.php" role="php">
  21163.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21164.    </file>
  21165.    <file md5sum="a173a2ff92d2a93d7153b101da34cf18" name="PEAR/PackageFile/Parser/v2.php" role="php">
  21166.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21167.    </file>
  21168.    <file md5sum="2656bd7b445c1885072ad2a25e8dfd0e" name="PEAR/PackageFile/v2/rw.php" role="php">
  21169.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21170.    </file>
  21171.    <file md5sum="5b702d0d25f40e889b9bd205b655fb16" name="PEAR/PackageFile/v2/Validator.php" role="php">
  21172.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21173.    </file>
  21174.    <file md5sum="30d4ddc15dfc592389411d99a2dd3b37" name="PEAR/PackageFile/v1.php" role="php">
  21175.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21176.    </file>
  21177.    <file md5sum="2a36cf4ff04777f950c9afd2aad468a1" name="PEAR/PackageFile/v2.php" role="php">
  21178.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21179.    </file>
  21180.    <file md5sum="8b309d72a3c773429dea666696d9888e" name="PEAR/REST/10.php" role="php">
  21181.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21182.    </file>
  21183.    <file md5sum="08fee3e5c8443e5ebafc17bb13959b62" name="PEAR/REST/11.php" role="php">
  21184.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21185.    </file>
  21186.    <file md5sum="311c875b56dcda3f8848c22d1fc3d0f8" name="PEAR/Task/Postinstallscript/rw.php" role="php">
  21187.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21188.    </file>
  21189.    <file md5sum="09eb8d30ef25a47f1975a2447264f645" name="PEAR/Task/Replace/rw.php" role="php">
  21190.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21191.    </file>
  21192.    <file md5sum="b9afa2dcef500ac15885e01647f454b5" name="PEAR/Task/Unixeol/rw.php" role="php">
  21193.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21194.    </file>
  21195.    <file md5sum="631e7a866fc9921e0b9f2d45b68a1687" name="PEAR/Task/Windowseol/rw.php" role="php">
  21196.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21197.    </file>
  21198.    <file md5sum="1f0757906fc64708103e19bac2b3a4d5" name="PEAR/Task/Common.php" role="php">
  21199.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21200.    </file>
  21201.    <file md5sum="5815d0ea19cd0a4f00cb1e8e2e9eb163" name="PEAR/Task/Postinstallscript.php" role="php">
  21202.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21203.    </file>
  21204.    <file md5sum="0cba8e6997e694aa4452a0041aaa4228" name="PEAR/Task/Replace.php" role="php">
  21205.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21206.    </file>
  21207.    <file md5sum="d33a1fb9258fbbc780b2d07d81d3af46" name="PEAR/Task/Unixeol.php" role="php">
  21208.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21209.    </file>
  21210.    <file md5sum="4f8233e21872e0fcd63efa556d63a3fc" name="PEAR/Task/Windowseol.php" role="php">
  21211.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21212.    </file>
  21213.    <file md5sum="16fba26b50c17e2752c9ad82f96f102c" name="PEAR/Validator/PECL.php" role="php">
  21214.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21215.    </file>
  21216.    <file md5sum="5ce65e09af7eb738c639141838c6f26a" name="PEAR/Autoloader.php" role="php">
  21217.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21218.    </file>
  21219.    <file md5sum="ece2de8def8f8dd7f665b00e6694cc07" name="PEAR/Builder.php" role="php">
  21220.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  21221.    </file>
  21222.    <file md5sum="d6f16bff9405077e918a8f7be9e31fcf" name="PEAR/ChannelFile.php" role="php">
  21223.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21224.    </file>
  21225.    <file md5sum="7a6a51d4986f04e15e53fbe96fae6a9b" name="PEAR/Command.php" role="php">
  21226.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21227.    </file>
  21228.    <file md5sum="d24d08cc90e7d3fd03277806ac016b34" name="PEAR/Common.php" role="php">
  21229.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21230.    </file>
  21231.    <file md5sum="50af115a5d8fa85ee5f3068d172292d1" name="PEAR/Config.php" role="php">
  21232.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21233.    </file>
  21234.    <file md5sum="f42d5ae2639dd67b90b890ac2b0e6e56" name="PEAR/Dependency.php" role="php" />
  21235.    <file md5sum="23082dcb6a8a754c9a2fd093a81cfde5" name="PEAR/DependencyDB.php" role="php">
  21236.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21237.    </file>
  21238.    <file md5sum="82befcf59d8a42ab9283134649179ebc" name="PEAR/Dependency2.php" role="php">
  21239.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  21240.    </file>
  21241.    <file md5sum="15764f5cf89d436c9c5fa06d4652a912" name="PEAR/Downloader.php" role="php">
  21242.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21243.    </file>
  21244.    <file md5sum="594630ac0ef25c775ef31d1c9bb3c8e6" name="PEAR/ErrorStack.php" role="php">
  21245.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21246.    </file>
  21247.    <file md5sum="985799a0d417427029cff74f1c7e94d6" name="PEAR/Exception.php" role="php">
  21248.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21249.    </file>
  21250.    <file md5sum="e6692dee75572336cb7b4ebea6699312" name="PEAR/Frontend.php" role="php">
  21251.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21252.    </file>
  21253.    <file md5sum="16871c2327ab0a6372a64ec4a91308cd" name="PEAR/Installer.php" role="php">
  21254.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21255.    </file>
  21256.    <file md5sum="7fce4e17c75790a7800dd61a6e2a1314" name="PEAR/PackageFile.php" role="php">
  21257.     <tasks:replace from="@PEAR-VER@" to="version" type="package-info" />
  21258.    </file>
  21259.    <file md5sum="89fbe13ab1e56bb98e2f026669a8a749" name="PEAR/Packager.php" role="php">
  21260.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21261.    </file>
  21262.    <file md5sum="c008052d80ba8bf49a80b6f4a224ff78" name="PEAR/Registry.php" role="php">
  21263.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21264.    </file>
  21265.    <file md5sum="b9df405a9c72526de21053d305251eec" name="PEAR/Remote.php" role="php">
  21266.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21267.    </file>
  21268.    <file md5sum="882d0d90865afc47d746e54748ded42a" name="PEAR/REST.php" role="php">
  21269.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21270.    </file>
  21271.    <file md5sum="dd390ae06a1284fd54e5ac5e7efe87e2" name="PEAR/RunTest.php" role="php">
  21272.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21273.    </file>
  21274.    <file md5sum="f15a4b531bd9750a17639a4201f9abbc" name="PEAR/Validate.php" role="php">
  21275.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21276.    </file>
  21277.    <file md5sum="4708bbff52de958814b6ac2e22070e56" name="PEAR/XMLParser.php" role="php">
  21278.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21279.    </file>
  21280.    <file baseinstalldir="/" md5sum="000e0141cccb734d87df52d4c5cb110b" name="scripts/pear.bat" role="script">
  21281.     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  21282.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  21283.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  21284.     <tasks:windowseol />
  21285.    </file>
  21286.    <file baseinstalldir="/" md5sum="481c8b236e565dd41c7746a37b40e3d6" name="scripts/peardev.bat" role="script">
  21287.     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  21288.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  21289.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  21290.     <tasks:windowseol />
  21291.    </file>
  21292.    <file baseinstalldir="/" md5sum="5b79b05dd0b0061086cea4ea770c9f78" name="scripts/pecl.bat" role="script">
  21293.     <tasks:replace from="@bin_dir@" to="bin_dir" type="pear-config" />
  21294.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  21295.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  21296.     <tasks:windowseol />
  21297.    </file>
  21298.    <file baseinstalldir="/" md5sum="98cc2576a216aaffc63d2137c792d8a2" name="scripts/pear.sh" role="script">
  21299.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  21300.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  21301.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  21302.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  21303.     <tasks:unixeol />
  21304.    </file>
  21305.    <file baseinstalldir="/" md5sum="0ee5f6671cbe9d4345257458c2d9afeb" name="scripts/peardev.sh" role="script">
  21306.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  21307.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  21308.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  21309.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  21310.     <tasks:unixeol />
  21311.    </file>
  21312.    <file baseinstalldir="/" md5sum="9c4a96de81bb720a648b0fdca1446584" name="scripts/pecl.sh" role="script">
  21313.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  21314.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  21315.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  21316.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  21317.     <tasks:unixeol />
  21318.    </file>
  21319.    <file baseinstalldir="/" md5sum="e9a69d7f64cc24ba2ad488eeee03a323" name="scripts/pearcmd.php" role="php">
  21320.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  21321.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  21322.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  21323.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  21324.    </file>
  21325.    <file baseinstalldir="/" md5sum="6356b5beefa80d0bbfd234d222873c7d" name="scripts/peclcmd.php" role="php">
  21326.     <tasks:replace from="@php_bin@" to="php_bin" type="pear-config" />
  21327.     <tasks:replace from="@php_dir@" to="php_dir" type="pear-config" />
  21328.     <tasks:replace from="@pear_version@" to="version" type="package-info" />
  21329.     <tasks:replace from="@include_path@" to="php_dir" type="pear-config" />
  21330.    </file>
  21331.    <file md5sum="ca444da9174e05f8a0dc71d8ee47900f" name="package.dtd" role="data" />
  21332.    <file md5sum="5b404cc7109d0772fb757707e4c8fa56" name="PEAR.php" role="php">
  21333.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21334.    </file>
  21335.    <file md5sum="280dd4d725a486ffff1605aa16c77a6e" name="System.php" role="php">
  21336.     <tasks:replace from="@package_version@" to="version" type="package-info" />
  21337.    </file>
  21338.    <file md5sum="acd010e3bc43c0f72df584acde7b9158" name="template.spec" role="data" />
  21339.   </dir>
  21340.  </contents>
  21341.  <dependencies>
  21342.   <required>
  21343.    <php>
  21344.     <min>4.2</min>
  21345.    </php>
  21346.    <pearinstaller>
  21347.     <min>1.4.0a12</min>
  21348.    </pearinstaller>
  21349.    <package>
  21350.     <name>Archive_Tar</name>
  21351.     <channel>pear.php.net</channel>
  21352.     <min>1.1</min>
  21353.     <recommended>1.3.1</recommended>
  21354.     <exclude>1.3.0</exclude>
  21355.    </package>
  21356.    <package>
  21357.     <name>Console_Getopt</name>
  21358.     <channel>pear.php.net</channel>
  21359.     <min>1.2</min>
  21360.     <recommended>1.2</recommended>
  21361.    </package>
  21362.    <package>
  21363.     <name>PEAR_Frontend_Web</name>
  21364.     <channel>pear.php.net</channel>
  21365.     <max>0.5.0</max>
  21366.     <conflicts />
  21367.    </package>
  21368.    <package>
  21369.     <name>PEAR_Frontend_Gtk</name>
  21370.     <channel>pear.php.net</channel>
  21371.     <max>0.4.0</max>
  21372.     <exclude>0.4.0</exclude>
  21373.     <conflicts />
  21374.    </package>
  21375.    <extension>
  21376.     <name>xml</name>
  21377.    </extension>
  21378.    <extension>
  21379.     <name>pcre</name>
  21380.    </extension>
  21381.   </required>
  21382.   <optional>
  21383.    <package>
  21384.     <name>XML_RPC</name>
  21385.     <channel>pear.php.net</channel>
  21386.     <min>1.4.0</min>
  21387.    </package>
  21388.   </optional>
  21389.   <group hint="PEAR's web-based installer" name="webinstaller">
  21390.    <package>
  21391.     <name>PEAR_Frontend_Web</name>
  21392.     <channel>pear.php.net</channel>
  21393.     <min>0.5.1</min>
  21394.    </package>
  21395.   </group>
  21396.   <group hint="PEAR's PHP-GTK-based installer" name="gtkinstaller">
  21397.    <package>
  21398.     <name>PEAR_Frontend_Gtk</name>
  21399.     <channel>pear.php.net</channel>
  21400.     <min>0.4.0</min>
  21401.    </package>
  21402.   </group>
  21403.   <group hint="PEAR's PHP-GTK2-based installer" name="gtk2installer">
  21404.    <package>
  21405.     <name>PEAR_Frontend_Gtk2</name>
  21406.     <channel>pear.php.net</channel>
  21407.     <min>0.1.2</min>
  21408.    </package>
  21409.   </group>
  21410.  </dependencies>
  21411.  <phprelease>
  21412.   <installconditions>
  21413.    <os>
  21414.     <name>windows</name>
  21415.    </os>
  21416.   </installconditions>
  21417.   <filelist>
  21418.    <install as="pear.bat" name="scripts/pear.bat" />
  21419.    <install as="peardev.bat" name="scripts/peardev.bat" />
  21420.    <install as="pecl.bat" name="scripts/pecl.bat" />
  21421.    <install as="pearcmd.php" name="scripts/pearcmd.php" />
  21422.    <install as="peclcmd.php" name="scripts/peclcmd.php" />
  21423.    <ignore name="scripts/peardev.sh" />
  21424.    <ignore name="scripts/pear.sh" />
  21425.    <ignore name="scripts/pecl.sh" />
  21426.   </filelist>
  21427.  </phprelease>
  21428.  <phprelease>
  21429.   <filelist>
  21430.    <install as="pear" name="scripts/pear.sh" />
  21431.    <install as="peardev" name="scripts/peardev.sh" />
  21432.    <install as="pecl" name="scripts/pecl.sh" />
  21433.    <install as="pearcmd.php" name="scripts/pearcmd.php" />
  21434.    <install as="peclcmd.php" name="scripts/peclcmd.php" />
  21435.    <ignore name="scripts/pear.bat" />
  21436.    <ignore name="scripts/peardev.bat" />
  21437.    <ignore name="scripts/pecl.bat" />
  21438.   </filelist>
  21439.  </phprelease>
  21440.  <changelog>
  21441.   <release>
  21442.    <date>2006-07-18</date>
  21443.    <version>
  21444.     <release>1.4.10</release>
  21445.     <api>1.4.2</api>
  21446.    </version>
  21447.    <stability>
  21448.     <release>stable</release>
  21449.     <api>stable</api>
  21450.    </stability>
  21451.    <license uri="http://www.php.net/license">PHP License</license>
  21452.    <notes>bugfix release
  21453. * fix Bug #7579: cannot convert package 1.0 to 2.0 with PFM 1.6.0
  21454. * fix Bug #7640: Check invalid date format
  21455. * fix Bug #7726: <uri> dependency is broken
  21456. * fix Bug #7830: Warning in package-dependencies command when a dir is used
  21457. * fix Bug #7842: package-dependencies wrong type display with package 1.0 
  21458. * fix Bug #8230: pear help channel-discover shows wrong text
  21459. * fix many open_basedir issues
  21460. * fix an issue in the better state detection
  21461. * fix typo in pickle command that would allow pickling of non-PECL package.xml
  21462. * implement Request #7090: PEAR_Downloader mustn't contact pear server
  21463.   when installing local package file
  21464. * implement Request #7844: download_dir and temp_dir configuration option
  21465. * check pearinstaller dependency prior to validating package.xml 2.0</notes>
  21466.   </release>
  21467.   <release>
  21468.    <version>
  21469.     <release>1.4.0</release>
  21470.     <api>1.4.0</api>
  21471.    </version>
  21472.    <stability>
  21473.     <release>stable</release>
  21474.     <api>stable</api>
  21475.    </stability>
  21476.    <date>2005-09-18</date>
  21477.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21478.    <notes>This is a major milestone release for PEAR.  In addition to several killer features,
  21479. every single element of PEAR has a regression test, and so stability is much higher
  21480. than any previous PEAR release.
  21481. New features in a nutshell:
  21482. * full support for channels
  21483. * pre-download dependency validation
  21484. * new package.xml 2.0 format allows tremendous flexibility while maintaining BC
  21485. * support for optional dependency groups and limited support for sub-packaging
  21486. * robust dependency support
  21487. * full dependency validation on uninstall
  21488. * remote install for hosts with only ftp access - no more problems with
  21489.   restricted host installation [through PEAR_RemoteInstaller package]
  21490. * full support for mirroring
  21491. * support for bundling several packages into a single tarball
  21492. * support for static dependencies on a uri-based package
  21493. * support for custom file roles and installation tasks
  21494. NOTE: users of PEAR_Frontend_Web/PEAR_Frontend_Gtk must upgrade their installations
  21495. to the latest version, or PEAR will not upgrade properly</notes>
  21496.   </release>
  21497.   <release>
  21498.    <version>
  21499.     <release>1.4.1</release>
  21500.     <api>1.4.0</api>
  21501.    </version>
  21502.    <stability>
  21503.     <release>stable</release>
  21504.     <api>stable</api>
  21505.    </stability>
  21506.    <date>2005-09-25</date>
  21507.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21508.    <notes>Major bugfix release.  This is a recommended download for ALL PEAR users
  21509.  
  21510. UPGRADING FROM 1.4.0 WILL CAUSE A SERIES OF NOTICES.  IGNORE THEM.
  21511. THIS IS CAUSED BY A BUG IN 1.4.0 THAT IS FIXED IN 1.4.1
  21512. * fix prompt processing in post-install scripts
  21513. * make dual package.xml equivalency stricter when using package.xml/package2.xml
  21514. * fix critical error in validating bogus php dependencies of package.xml 1.0
  21515.   This error has existed for every PEAR version, and allows dependencies like:
  21516.   <dep type="php" rel="has">4.3.0</dep> to
  21517.   slip through unnoticed
  21518. * re-enable php-const replacements
  21519. * PEAR_PackageFile_v2::getConfigureOptions() was missing!!
  21520. * fix cvsdiff command
  21521. * fix xml encoding issues finally
  21522. * clean up package.xml 1.0 dir/file parsing
  21523. * fix invalid PEAR_Config generation
  21524. * change the user agent from PHP/phpversion to PEAR/pearversion/PHP/phpversion
  21525. * don't use a bogus uri for licenses on running convert command
  21526. * add "pickle" command for PECL packaging
  21527. * add validation warning if the release date in package.xml is not today when packaging
  21528. * implement progress bar for list-all/remote-list
  21529. * fix Bug #5323: pear search returns odd version numbers
  21530. * fix Bug #5428: pear cvstag package2.xml does not include the package.xml
  21531. * fix Bug #5449: pear makerpm completely broken for package.xml 2.0
  21532. * fix Bug #5462: raiseError method does not return by ref anymore
  21533. * fix Bug #5465: pear install --offline fails to display error
  21534. * fix Bug #5477: Bug in Downloader.php and Dependency2.php
  21535. * fix Bug #5481: "pear install PECLextension" should display warning to use pecl command
  21536. * fix Bug #5482: installation of PECL packages should say add extensions to php.ini
  21537. * fix Bug #5483: pecl uninstall crack fatal error
  21538. * fix Bug #5487: PECL: compiled files are not uninstalled via the uninstall command
  21539. * fix Bug #5488: pecl uninstall package fails if package has a package.xml 1.0
  21540. * fix Bug #5501: the commands list mentions XML-RPC
  21541. * fix Bug #5509: addDependecyGroup does not validate group name
  21542. * fix Bug #5513: PEAR 1.4 does not install non-pear.php.net packages</notes>
  21543.   </release>
  21544.   <release>
  21545.    <version>
  21546.     <release>1.4.2</release>
  21547.     <api>1.4.0</api>
  21548.    </version>
  21549.    <stability>
  21550.     <release>stable</release>
  21551.     <api>stable</api>
  21552.    </stability>
  21553.    <date>2005-10-08</date>
  21554.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21555.    <notes>Minor bugfix release
  21556. * fix issues with API for adding tasks to package2.xml
  21557. * fix Bug #5520: pecl pickle fails on pecl pickle fails on extension/package deps
  21558. * fix Bug #5523: pecl pickle misses to put configureoptions into package.xml v1
  21559. * fix Bug #5527: No need for cpp
  21560. * fix Bug #5529: configure options in package.xml 2.0 will be ignored
  21561. * fix Bug #5530: PEAR_PackageFile_v2->getConfigureOptions() API incompatible with v1
  21562. * fix Bug #5531: adding of installconditions/binarypackage/configure options
  21563.                  to extsrc may fail
  21564. * fix Bug #5550: PHP notices/warnings/errors are 1 file off in trace
  21565. * fix Bug #5580: pear makerpm XML_sql2xml-0.3.2.tgz error
  21566. * fix Bug #5619: pear makerpm produces invalid .spec dependancy code
  21567. * fix Bug #5629: pear install http_download dies with bad error message</notes>
  21568.   </release>
  21569.   <release>
  21570.    <version>
  21571.     <release>1.4.3</release>
  21572.     <api>1.4.1</api>
  21573.    </version>
  21574.    <stability>
  21575.     <release>stable</release>
  21576.     <api>stable</api>
  21577.    </stability>
  21578.    <date>2005-11-03</date>
  21579.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21580.    <notes>MINOR SECURITY FIX release
  21581. A security vulnerability has been discovered in all
  21582. PEAR versions (1.0 to 1.4.2).  This vulnerability has been fixed, 
  21583. and this is a recommended upgrade for all users.
  21584. Run "pear channel-update" after upgrading for exponentially
  21585. faster list-all/remote-list!!
  21586. * fix installation of files named like ".test"
  21587. * fix base class for writeable unixeol/windowseol classes
  21588. * fix running of post-install scripts with empty or no paramgroup
  21589.   in CLI frontend
  21590. * fix validation of <postinstallscript>
  21591. * fix writeable PEAR_Task_Postinstallscript_rw class
  21592. * fix error in REST-based search command if searching through description
  21593.   as well
  21594. * silence warning on list-upgrades/upgrade-all if no releases exist at a channel
  21595. * add checks for updated channel.xml in all remote commands
  21596. * fix pecl script if safe_mode is enabled by default
  21597. * implement SERIOUS improvement in list-all/remote-list speed.  From 6 minutes
  21598.   down to about 16-30 seconds
  21599. * implement --loose option to avoid recommended version validation
  21600. * implement Request #5527: alternative approach to determining glibc version
  21601. * fix Bug #5717: analyzeSourceCode() fails to process certain
  21602.   quote situations properly
  21603. * fix Bug #5736: if registry can't lock registry or open filemap,
  21604.   checkFileMap(), no error
  21605. * fix Bug #5676: pear config-create broken
  21606. * fix Bug #5683: Deadlock with (almost) circular dependency
  21607. * fix Bug #5725: PHP5 warnings need improvement
  21608. * fix Bug #5789: small typo
  21609. * fix Bug #5810: internet should not be contacted on install if dependencies are installed</notes>
  21610.   </release>
  21611.   <release>
  21612.    <version>
  21613.     <release>1.4.4</release>
  21614.     <api>1.4.1</api>
  21615.    </version>
  21616.    <stability>
  21617.     <release>stable</release>
  21618.     <api>stable</api>
  21619.    </stability>
  21620.    <date>2005-11-04</date>
  21621.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21622.    <notes>* fix Bug #5865: doesn't work with PHP4.2.x</notes>
  21623.   </release>
  21624.   <release>
  21625.    <version>
  21626.     <release>1.4.5</release>
  21627.     <api>1.4.1</api>
  21628.    </version>
  21629.    <stability>
  21630.     <release>stable</release>
  21631.     <api>stable</api>
  21632.    </stability>
  21633.    <date>2005-11-21</date>
  21634.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21635.    <notes>* REALLY fix Bug #5865: doesn't work with PHP4.2.x
  21636. * fix Bug #5854: if no installconditions match, no error is raised
  21637. * fix Bug #5945: installer should auto-skip to the next channel on timeout
  21638. * fix Bug #5947: Some package-info not handled by PEAR_PackageFile_v2
  21639. * fix Bug #5948: Minor typo in PEAR_Validate
  21640. * fix Bug #5958: strange error on mistyping
  21641. * fix Bug #5959: patch: pear makerpm produces RPMs that do not uninstall/upgrade cleanly</notes>
  21642.   </release>
  21643.   <release>
  21644.    <version>
  21645.     <release>1.4.6</release>
  21646.     <api>1.4.1</api>
  21647.    </version>
  21648.    <stability>
  21649.     <release>stable</release>
  21650.     <api>stable</api>
  21651.    </stability>
  21652.    <date>2006-01-06</date>
  21653.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21654.    <notes>Minor bugfix release
  21655. * fix problem with -options when using CGI version of PHP
  21656. * fix Critical Bug #5999: support for baseinstalldir broken in package2.xml format
  21657. * fix Bug #6034: date format bug
  21658. * fix Bug #6040: PEAR_Frontend#setFrontendClass has no docblock;
  21659.   PEAR_Frontend not documented
  21660. * fix Bug #6044: PEAR_REST::retrieveCacheFirst doesn't return error codes
  21661. * fix Bug #6047: pear makerpm fails to handle docs in root directory
  21662. * fix Bug #6048: PEAR_Frontend::log parameters are wrong
  21663. * fix Bug #6106: Notices by list-upgrades (caused by time-outs ?)
  21664. * fix Bug #6145: Can't install PEAR with INSTALL_ROOT environment
  21665. * fix Bug #6218: the "pear" command does nothing
  21666. * fix Bug #6269: System::which() returns silliness if passed null
  21667. * fix Bug #6322: Installer fails to follow redirects [patch by Bertrand Gugger]
  21668. * fix Request #6119: Add PEAR_Frontend_Gtk2 support to PEAR</notes>
  21669.   </release>
  21670.   <release>
  21671.    <version>
  21672.     <release>1.4.7</release>
  21673.     <api>1.4.1</api>
  21674.    </version>
  21675.    <stability>
  21676.     <release>stable</release>
  21677.     <api>stable</api>
  21678.    </stability>
  21679.    <date>2006-02-27</date>
  21680.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21681.    <notes>Minor bugfix release
  21682. * Prevent packaging of release candidate releases with versions like 1.0.0rc1
  21683.   version_compare() only understands upper-case 1.0.0RC1
  21684. * implement CLEAN section in .phpt tests
  21685. * implement run-tests command for phpunit-based tests
  21686. * implement Request #6039: setFrontendObject needed to allow objects passed
  21687. * fix Bug #6075: unnecessary validation of maintainers can break PEAR_PFM
  21688. * fix Bug #6076: optional is not set for conversion of package2.xml to "has" rel
  21689. * fix Bug #6077: PEAR_PackageFile_Parser_v2 should return by reference
  21690. * fix Bug #6273: pear download-all fails
  21691. * fix Bug #6383: incomplete PEAR::Error message on addReplacement()
  21692. * fix Bug #6445: PEAR::registerShutdownFunc doesn't work in static calls
  21693. * fix Bug #6480: pear install --installroot option fails for pecl packages [timj]
  21694. * fix Bug #6510: status active of a maintainer cannot be change
  21695. * fix Bug #6537: wrong export compatible v1 dependencies list with exclude limit
  21696. * fix Bug #6559: pear should ignore safemode/open_basedir
  21697. * fix Bug #6576: PFM2 run in trouble with sessions
  21698. * fix Bug #6579: PFM2 changelog and license with uri
  21699. * fix Bug #6673: pear install --offline --packagingroot=/blah does not work
  21700. * fix Bug #6674: --packagingroot always uses channel pear.php.net configuration
  21701. * fix Bug #6675: postinstallscript validation fails
  21702. * fix Bug #6690: channel with / will not allow upgrade
  21703. * fix Bug #6692: Optional feature install message needs channel name
  21704. * fix Bug #6716: "pear install -r" errors after install when
  21705.                  attempting "pear list <pkgname>"
  21706. * fix Bug #6735: PEAR_PackageFile::fromTgzFile doesn't work with package.xml
  21707.                  not in root dir</notes>
  21708.   </release>
  21709.   <release>
  21710.    <version>
  21711.     <release>1.4.8</release>
  21712.     <api>1.4.2</api>
  21713.    </version>
  21714.    <stability>
  21715.     <release>stable</release>
  21716.     <api>stable</api>
  21717.    </stability>
  21718.    <date>2006-03-05</date>
  21719.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21720.    <notes>CRITICAL BUGFIX RELEASE
  21721.  
  21722. Channels with "-" in their name were suddenly invalid, and
  21723. caused crashes in many places due to improper error handling
  21724. * fix Bug #6960: channels are not allowed to have "-" in their name
  21725. * fix critical Bug #6969: PEAR list-upgrades crashes
  21726. * fix Bug #6991: Class 'PEAR_PackageFile_v1' not found in Registry.php at line 1657
  21727. * fix Bug #7008: PEAR_Frontend::setFrontendObject doesn't set the object
  21728. * fix Bug #7015: install a package.tgz with unknown channel, fatal error in PEAR/Registry.php
  21729. * fix Bug #7020: tests/PEAR_Registry/api1_1/test_getChannelValidator.phpt crashes PEAR</notes>
  21730.   </release>
  21731.   <release>
  21732.    <version>
  21733.     <release>1.4.9</release>
  21734.     <api>1.4.2</api>
  21735.    </version>
  21736.    <stability>
  21737.     <release>stable</release>
  21738.     <api>stable</api>
  21739.    </stability>
  21740.    <date>2006-03-29</date>
  21741.    <license uri="http://www.php.net/license/3_0.txt">PHP License</license>
  21742.    <notes>CRITICAL BUGFIX RELEASE
  21743. users upgrading from PEAR 1.3.x cannot upgrade to 1.4.8
  21744. users who use --packagingroot may find that installation fails
  21745. * fix Bug #7093: if pear channel does not exist, it cannot be retrieved
  21746. * fix Bug #7165: warnings in pear
  21747. * fix Bug #7075: PEAR_PackageFile_v2 :: setLogger failed on autodetection</notes>
  21748.   </release>
  21749.  </changelog>
  21750. </package>
  21751. PEAR-1.4.11/OS/Guess.php100644   1750   1750       25423 10470570063   7717 <?php
  21752. /**
  21753.  * The OS_Guess class
  21754.  *
  21755.  * PHP versions 4 and 5
  21756.  *
  21757.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  21758.  * that is available through the world-wide-web at the following URI:
  21759.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  21760.  * the PHP License and are unable to obtain it through the web, please
  21761.  * send a note to license@php.net so we can mail you a copy immediately.
  21762.  *
  21763.  * @category   pear
  21764.  * @package    PEAR
  21765.  * @author     Stig Bakken <ssb@php.net>
  21766.  * @author     Gregory Beaver <cellog@php.net>
  21767.  * @copyright  1997-2005 The PHP Group
  21768.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  21769.  * @version    CVS: $Id: Guess.php,v 1.20.2.1 2006/06/16 11:41:16 pajoye Exp $
  21770.  * @link       http://pear.php.net/package/PEAR
  21771.  * @since      File available since PEAR 0.1
  21772.  */
  21773.  
  21774. // {{{ uname examples
  21775.  
  21776. // php_uname() without args returns the same as 'uname -a', or a PHP-custom
  21777. // string for Windows.
  21778. // PHP versions prior to 4.3 return the uname of the host where PHP was built,
  21779. // as of 4.3 it returns the uname of the host running the PHP code.
  21780. //
  21781. // PC RedHat Linux 7.1:
  21782. // Linux host.example.com 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown
  21783. //
  21784. // PC Debian Potato:
  21785. // Linux host 2.4.17 #2 SMP Tue Feb 12 15:10:04 CET 2002 i686 unknown
  21786. //
  21787. // PC FreeBSD 3.3:
  21788. // FreeBSD host.example.com 3.3-STABLE FreeBSD 3.3-STABLE #0: Mon Feb 21 00:42:31 CET 2000     root@example.com:/usr/src/sys/compile/CONFIG  i386
  21789. //
  21790. // PC FreeBSD 4.3:
  21791. // FreeBSD host.example.com 4.3-RELEASE FreeBSD 4.3-RELEASE #1: Mon Jun 25 11:19:43 EDT 2001     root@example.com:/usr/src/sys/compile/CONFIG  i386
  21792. //
  21793. // PC FreeBSD 4.5:
  21794. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb  6 23:59:23 CET 2002     root@example.com:/usr/src/sys/compile/CONFIG  i386
  21795. //
  21796. // PC FreeBSD 4.5 w/uname from GNU shellutils:
  21797. // FreeBSD host.example.com 4.5-STABLE FreeBSD 4.5-STABLE #0: Wed Feb  i386 unknown
  21798. //
  21799. // HP 9000/712 HP-UX 10:
  21800. // HP-UX iq B.10.10 A 9000/712 2008429113 two-user license
  21801. //
  21802. // HP 9000/712 HP-UX 10 w/uname from GNU shellutils:
  21803. // HP-UX host B.10.10 A 9000/712 unknown
  21804. //
  21805. // IBM RS6000/550 AIX 4.3:
  21806. // AIX host 3 4 000003531C00
  21807. //
  21808. // AIX 4.3 w/uname from GNU shellutils:
  21809. // AIX host 3 4 000003531C00 unknown
  21810. //
  21811. // SGI Onyx IRIX 6.5 w/uname from GNU shellutils:
  21812. // IRIX64 host 6.5 01091820 IP19 mips
  21813. //
  21814. // SGI Onyx IRIX 6.5:
  21815. // IRIX64 host 6.5 01091820 IP19
  21816. //
  21817. // SparcStation 20 Solaris 8 w/uname from GNU shellutils:
  21818. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc
  21819. //
  21820. // SparcStation 20 Solaris 8:
  21821. // SunOS host.example.com 5.8 Generic_108528-12 sun4m sparc SUNW,SPARCstation-20
  21822. //
  21823. // Mac OS X (Darwin)
  21824. // Darwin home-eden.local 7.5.0 Darwin Kernel Version 7.5.0: Thu Aug  5 19:26:16 PDT 2004; root:xnu/xnu-517.7.21.obj~3/RELEASE_PPC  Power Macintosh
  21825. //
  21826. // Mac OS X early versions
  21827. // 
  21828.  
  21829. // }}}
  21830.  
  21831. /* TODO:
  21832.  * - define endianness, to allow matchSignature("bigend") etc.
  21833.  */
  21834.  
  21835. /**
  21836.  * Retrieves information about the current operating system
  21837.  *
  21838.  * This class uses php_uname() to grok information about the current OS
  21839.  *
  21840.  * @category   pear
  21841.  * @package    PEAR
  21842.  * @author     Stig Bakken <ssb@php.net>
  21843.  * @author     Gregory Beaver <cellog@php.net>
  21844.  * @copyright  1997-2005 The PHP Group
  21845.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  21846.  * @version    Release: 1.4.11
  21847.  * @link       http://pear.php.net/package/PEAR
  21848.  * @since      Class available since Release 0.1
  21849.  */
  21850. class OS_Guess
  21851. {
  21852.     var $sysname;
  21853.     var $nodename;
  21854.     var $cpu;
  21855.     var $release;
  21856.     var $extra;
  21857.  
  21858.     function OS_Guess($uname = null)
  21859.     {
  21860.         list($this->sysname,
  21861.              $this->release,
  21862.              $this->cpu,
  21863.              $this->extra,
  21864.              $this->nodename) = $this->parseSignature($uname);
  21865.     }
  21866.  
  21867.     function parseSignature($uname = null)
  21868.     {
  21869.         static $sysmap = array(
  21870.             'HP-UX' => 'hpux',
  21871.             'IRIX64' => 'irix',
  21872.         );
  21873.         static $cpumap = array(
  21874.             'i586' => 'i386',
  21875.             'i686' => 'i386',
  21876.             'ppc' => 'powerpc',
  21877.         );
  21878.         if ($uname === null) {
  21879.             $uname = php_uname();
  21880.         }
  21881.         $parts = split('[[:space:]]+', trim($uname));
  21882.         $n = count($parts);
  21883.  
  21884.         $release = $machine = $cpu = '';
  21885.         $sysname = $parts[0];
  21886.         $nodename = $parts[1];
  21887.         $cpu = $parts[$n-1];
  21888.         $extra = '';
  21889.         if ($cpu == 'unknown') {
  21890.             $cpu = $parts[$n-2];
  21891.         }
  21892.  
  21893.         switch ($sysname) {
  21894.             case 'AIX' :
  21895.                 $release = "$parts[3].$parts[2]";
  21896.                 break;
  21897.             case 'Windows' :
  21898.                 switch ($parts[1]) {
  21899.                     case '95/98':
  21900.                         $release = '9x';
  21901.                         break;
  21902.                     default:
  21903.                         $release = $parts[1];
  21904.                         break;
  21905.                 }
  21906.                 $cpu = 'i386';
  21907.                 break;
  21908.             case 'Linux' :
  21909.                 $extra = $this->_detectGlibcVersion();
  21910.                 // use only the first two digits from the kernel version
  21911.                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
  21912.                 break;
  21913.             case 'Mac' :
  21914.                 $sysname = 'darwin';
  21915.                 $nodename = $parts[2];
  21916.                 $release = $parts[3];
  21917.                 if ($cpu == 'Macintosh') {
  21918.                     if ($parts[$n - 2] == 'Power') {
  21919.                         $cpu = 'powerpc';
  21920.                     }
  21921.                 }
  21922.                 break;
  21923.             case 'Darwin' :
  21924.                 if ($cpu == 'Macintosh') {
  21925.                     if ($parts[$n - 2] == 'Power') {
  21926.                         $cpu = 'powerpc';
  21927.                     }
  21928.                 }
  21929.                 $release = ereg_replace('^([[:digit:]]+\.[[:digit:]]+).*', '\1', $parts[2]);
  21930.                 break;
  21931.             default:
  21932.                 $release = ereg_replace('-.*', '', $parts[2]);
  21933.                 break;
  21934.         }
  21935.  
  21936.  
  21937.         if (isset($sysmap[$sysname])) {
  21938.             $sysname = $sysmap[$sysname];
  21939.         } else {
  21940.             $sysname = strtolower($sysname);
  21941.         }
  21942.         if (isset($cpumap[$cpu])) {
  21943.             $cpu = $cpumap[$cpu];
  21944.         }
  21945.         return array($sysname, $release, $cpu, $extra, $nodename);
  21946.     }
  21947.  
  21948.     function _detectGlibcVersion()
  21949.     {
  21950.         static $glibc = false;
  21951.         if ($glibc !== false) {
  21952.             return $glibc; // no need to run this multiple times
  21953.         }
  21954.         include_once "System.php";
  21955.         if (!@file_exists('/usr/bin/cpp') || !@is_executable('/usr/bin/cpp')) {
  21956.             // Use glibc's <features.h> header file to
  21957.             // get major and minor version number:
  21958.             if (@file_exists('/usr/include/features.h') &&
  21959.                   @is_readable('/usr/include/features.h')) {
  21960.                 $features_file = fopen('/usr/include/features.h', 'rb');
  21961.                 while (!feof($features_file)) {
  21962.                     $line = fgets($features_file, 8192);
  21963.                     if (!$line || (strpos($line, '#define') === false)) {
  21964.                         continue;
  21965.                     }
  21966.                     if (strpos($line, '__GLIBC__')) {
  21967.                         // major version number #define __GLIBC__ version
  21968.                         $line = preg_split('/\s+/', $line);
  21969.                         $glibc_major = trim($line[2]);
  21970.                         if (isset($glibc_minor)) {
  21971.                             break;
  21972.                         }
  21973.                         continue;
  21974.                     }
  21975.                     if (strpos($line, '__GLIBC_MINOR__'))  {
  21976.                         // got the minor version number
  21977.                         // #define __GLIBC_MINOR__ version
  21978.                         $line = preg_split('/\s+/', $line);
  21979.                         $glibc_minor = trim($line[2]);
  21980.                         if (isset($glibc_major)) {
  21981.                             break;
  21982.                         }
  21983.                         continue;
  21984.                     }
  21985.                 }
  21986.                 fclose($features_file);
  21987.                 if (!isset($glibc_major) || !isset($glibc_minor)) {
  21988.                     return $glibc = '';
  21989.                 }
  21990.                 return $glibc = 'glibc' . trim($glibc_major) . "." . trim($glibc_minor) ;
  21991.             }
  21992.             return $glibc = '';
  21993.         }
  21994.         $tmpfile = System::mktemp("glibctest");
  21995.         $fp = fopen($tmpfile, "w");
  21996.         fwrite($fp, "#include <features.h>\n__GLIBC__ __GLIBC_MINOR__\n");
  21997.         fclose($fp);
  21998.         $cpp = popen("/usr/bin/cpp $tmpfile", "r");
  21999.         $major = $minor = 0;
  22000.         while ($line = fgets($cpp, 1024)) {
  22001.             if ($line{0} == '#' || trim($line) == '') {
  22002.                 continue;
  22003.             }
  22004.             if (list($major, $minor) = explode(' ', trim($line))) {
  22005.                 break;
  22006.             }
  22007.         }
  22008.         pclose($cpp);
  22009.         unlink($tmpfile);
  22010.         if (!($major && $minor) && is_link('/lib/libc.so.6')) {
  22011.             // Let's try reading the libc.so.6 symlink
  22012.             if (ereg('^libc-([.*])\.so$', basename(readlink('/lib/libc.so.6')), $matches)) {
  22013.                 list($major, $minor) = explode('.', $matches);
  22014.             }
  22015.         }
  22016.         if (!($major && $minor)) {
  22017.             return $glibc = '';
  22018.         }
  22019.         return $glibc = "glibc{$major}.{$minor}";
  22020.     }
  22021.  
  22022.     function getSignature()
  22023.     {
  22024.         if (empty($this->extra)) {
  22025.             return "{$this->sysname}-{$this->release}-{$this->cpu}";
  22026.         }
  22027.         return "{$this->sysname}-{$this->release}-{$this->cpu}-{$this->extra}";
  22028.     }
  22029.  
  22030.     function getSysname()
  22031.     {
  22032.         return $this->sysname;
  22033.     }
  22034.  
  22035.     function getNodename()
  22036.     {
  22037.         return $this->nodename;
  22038.     }
  22039.  
  22040.     function getCpu()
  22041.     {
  22042.         return $this->cpu;
  22043.     }
  22044.  
  22045.     function getRelease()
  22046.     {
  22047.         return $this->release;
  22048.     }
  22049.  
  22050.     function getExtra()
  22051.     {
  22052.         return $this->extra;
  22053.     }
  22054.  
  22055.     function matchSignature($match)
  22056.     {
  22057.         if (is_array($match)) {
  22058.             $fragments = $match;
  22059.         } else {
  22060.             $fragments = explode('-', $match);
  22061.         }
  22062.         $n = count($fragments);
  22063.         $matches = 0;
  22064.         if ($n > 0) {
  22065.             $matches += $this->_matchFragment($fragments[0], $this->sysname);
  22066.         }
  22067.         if ($n > 1) {
  22068.             $matches += $this->_matchFragment($fragments[1], $this->release);
  22069.         }
  22070.         if ($n > 2) {
  22071.             $matches += $this->_matchFragment($fragments[2], $this->cpu);
  22072.         }
  22073.         if ($n > 3) {
  22074.             $matches += $this->_matchFragment($fragments[3], $this->extra);
  22075.         }
  22076.         return ($matches == $n);
  22077.     }
  22078.  
  22079.     function _matchFragment($fragment, $value)
  22080.     {
  22081.         if (strcspn($fragment, '*?') < strlen($fragment)) {
  22082.             $reg = '^' . str_replace(array('*', '?', '/'), array('.*', '.', '\\/'), $fragment) . '$';
  22083.             return eregi($reg, $value);
  22084.         }
  22085.         return ($fragment == '*' || !strcasecmp($fragment, $value));
  22086.     }
  22087.  
  22088. }
  22089. /*
  22090.  * Local Variables:
  22091.  * indent-tabs-mode: nil
  22092.  * c-basic-offset: 4
  22093.  * End:
  22094.  */
  22095. ?>
  22096. PEAR-1.4.11/PEAR/ChannelFile/Parser.php100644   1750   1750        4121 10470570063  12413 <?php
  22097. /**
  22098.  * PEAR_ChannelFile_Parser for parsing channel.xml
  22099.  *
  22100.  * PHP versions 4 and 5
  22101.  *
  22102.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  22103.  * that is available through the world-wide-web at the following URI:
  22104.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  22105.  * the PHP License and are unable to obtain it through the web, please
  22106.  * send a note to license@php.net so we can mail you a copy immediately.
  22107.  *
  22108.  * @category   pear
  22109.  * @package    PEAR
  22110.  * @author     Greg Beaver <cellog@php.net>
  22111.  * @copyright  1997-2006 The PHP Group
  22112.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22113.  * @version    CVS: $Id: Parser.php,v 1.4 2006/01/06 04:47:36 cellog Exp $
  22114.  * @link       http://pear.php.net/package/PEAR
  22115.  * @since      File available since Release 1.4.0a1
  22116.  */
  22117.  
  22118. /**
  22119.  * base xml parser class
  22120.  */
  22121. require_once 'PEAR/XMLParser.php';
  22122. require_once 'PEAR/ChannelFile.php';
  22123. /**
  22124.  * Parser for channel.xml
  22125.  * @category   pear
  22126.  * @package    PEAR
  22127.  * @author     Greg Beaver <cellog@php.net>
  22128.  * @copyright  1997-2006 The PHP Group
  22129.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22130.  * @version    Release: 1.4.11
  22131.  * @link       http://pear.php.net/package/PEAR
  22132.  * @since      Class available since Release 1.4.0a1
  22133.  */
  22134. class PEAR_ChannelFile_Parser extends PEAR_XMLParser
  22135. {
  22136.     var $_config;
  22137.     var $_logger;
  22138.     var $_registry;
  22139.  
  22140.     function setConfig(&$c)
  22141.     {
  22142.         $this->_config = &$c;
  22143.         $this->_registry = &$c->getRegistry();
  22144.     }
  22145.  
  22146.     function setLogger(&$l)
  22147.     {
  22148.         $this->_logger = &$l;
  22149.     }
  22150.  
  22151.     function parse($data, $file)
  22152.     {
  22153.         if (PEAR::isError($err = parent::parse($data, $file))) {
  22154.             return $err;
  22155.         }
  22156.         $ret = new PEAR_ChannelFile;
  22157.         $ret->setConfig($this->_config);
  22158.         if (isset($this->_logger)) {
  22159.             $ret->setLogger($this->_logger);
  22160.         }
  22161.         $ret->fromArray($this->_unserializedData);
  22162.         // make sure the filelist is in the easy to read format needed
  22163.         $ret->flattenFilelist();
  22164.         $ret->setPackagefile($file, $archive);
  22165.         return $ret;
  22166.     }
  22167. }
  22168. ?>PEAR-1.4.11/PEAR/Command/Auth.xml100644   1750   1750        1620 10470570063  11300 <commands version="1.0">
  22169.  <login>
  22170.   <summary>Connects and authenticates to remote server</summary>
  22171.   <shortcut>li</shortcut>
  22172.   <function>doLogin</function>
  22173.   <options />
  22174.   <doc>
  22175. Log in to the remote server.  To use remote functions in the installer
  22176. that require any kind of privileges, you need to log in first.  The
  22177. username and password you enter here will be stored in your per-user
  22178. PEAR configuration (~/.pearrc on Unix-like systems).  After logging
  22179. in, your username and password will be sent along in subsequent
  22180. operations on the remote server.</doc>
  22181.  </login>
  22182.  <logout>
  22183.   <summary>Logs out from the remote server</summary>
  22184.   <shortcut>lo</shortcut>
  22185.   <function>doLogout</function>
  22186.   <options />
  22187.   <doc>
  22188. Logs out from the remote server.  This command does not actually
  22189. connect to the remote server, it only deletes the stored username and
  22190. password from your user configuration.</doc>
  22191.  </logout>
  22192. </commands>PEAR-1.4.11/PEAR/Command/Auth.php100644   1750   1750       12560 10470570063  11314 <?php
  22193. /**
  22194.  * PEAR_Command_Auth (login, logout commands)
  22195.  *
  22196.  * PHP versions 4 and 5
  22197.  *
  22198.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  22199.  * that is available through the world-wide-web at the following URI:
  22200.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  22201.  * the PHP License and are unable to obtain it through the web, please
  22202.  * send a note to license@php.net so we can mail you a copy immediately.
  22203.  *
  22204.  * @category   pear
  22205.  * @package    PEAR
  22206.  * @author     Stig Bakken <ssb@php.net>
  22207.  * @author     Greg Beaver <cellog@php.net>
  22208.  * @copyright  1997-2006 The PHP Group
  22209.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22210.  * @version    CVS: $Id: Auth.php,v 1.23 2006/03/02 18:14:13 cellog Exp $
  22211.  * @link       http://pear.php.net/package/PEAR
  22212.  * @since      File available since Release 0.1
  22213.  */
  22214.  
  22215. /**
  22216.  * base class
  22217.  */
  22218. require_once 'PEAR/Command/Common.php';
  22219. require_once 'PEAR/Config.php';
  22220.  
  22221. /**
  22222.  * PEAR commands for login/logout
  22223.  *
  22224.  * @category   pear
  22225.  * @package    PEAR
  22226.  * @author     Stig Bakken <ssb@php.net>
  22227.  * @author     Greg Beaver <cellog@php.net>
  22228.  * @copyright  1997-2006 The PHP Group
  22229.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22230.  * @version    Release: 1.4.11
  22231.  * @link       http://pear.php.net/package/PEAR
  22232.  * @since      Class available since Release 0.1
  22233.  */
  22234. class PEAR_Command_Auth extends PEAR_Command_Common
  22235. {
  22236.     // {{{ properties
  22237.  
  22238.     var $commands = array(
  22239.         'login' => array(
  22240.             'summary' => 'Connects and authenticates to remote server',
  22241.             'shortcut' => 'li',
  22242.             'function' => 'doLogin',
  22243.             'options' => array(),
  22244.             'doc' => '
  22245. Log in to the remote server.  To use remote functions in the installer
  22246. that require any kind of privileges, you need to log in first.  The
  22247. username and password you enter here will be stored in your per-user
  22248. PEAR configuration (~/.pearrc on Unix-like systems).  After logging
  22249. in, your username and password will be sent along in subsequent
  22250. operations on the remote server.',
  22251.             ),
  22252.         'logout' => array(
  22253.             'summary' => 'Logs out from the remote server',
  22254.             'shortcut' => 'lo',
  22255.             'function' => 'doLogout',
  22256.             'options' => array(),
  22257.             'doc' => '
  22258. Logs out from the remote server.  This command does not actually
  22259. connect to the remote server, it only deletes the stored username and
  22260. password from your user configuration.',
  22261.             )
  22262.  
  22263.         );
  22264.  
  22265.     // }}}
  22266.  
  22267.     // {{{ constructor
  22268.  
  22269.     /**
  22270.      * PEAR_Command_Auth constructor.
  22271.      *
  22272.      * @access public
  22273.      */
  22274.     function PEAR_Command_Auth(&$ui, &$config)
  22275.     {
  22276.         parent::PEAR_Command_Common($ui, $config);
  22277.     }
  22278.  
  22279.     // }}}
  22280.  
  22281.     // {{{ doLogin()
  22282.  
  22283.     /**
  22284.      * Execute the 'login' command.
  22285.      *
  22286.      * @param string $command command name
  22287.      *
  22288.      * @param array $options option_name => value
  22289.      *
  22290.      * @param array $params list of additional parameters
  22291.      *
  22292.      * @return bool TRUE on success or
  22293.      * a PEAR error on failure
  22294.      *
  22295.      * @access public
  22296.      */
  22297.     function doLogin($command, $options, $params)
  22298.     {
  22299.         $reg = &$this->config->getRegistry();
  22300.         $channel = $this->config->get('default_channel');
  22301.         $chan = $reg->getChannel($channel);
  22302.         if (PEAR::isError($chan)) {
  22303.             return $this->raiseError($chan);
  22304.         }
  22305.         $server = $this->config->get('preferred_mirror');
  22306.         $remote = &$this->config->getRemote();
  22307.         $username = $this->config->get('username');
  22308.         if (empty($username)) {
  22309.             $username = @$_ENV['USER'];
  22310.         }
  22311.         $this->ui->outputData("Logging in to $server.", $command);
  22312.         
  22313.         list($username, $password) = $this->ui->userDialog(
  22314.             $command,
  22315.             array('Username', 'Password'),
  22316.             array('text',     'password'),
  22317.             array($username,  '')
  22318.             );
  22319.         $username = trim($username);
  22320.         $password = trim($password);
  22321.         
  22322.         $this->config->set('username', $username);
  22323.         $this->config->set('password', $password);
  22324.  
  22325.         if ($chan->supportsREST()) {
  22326.             $ok = true;
  22327.         } else {
  22328.             $remote->expectError(401);
  22329.             $ok = $remote->call('logintest');
  22330.             $remote->popExpect();
  22331.         }
  22332.         if ($ok === true) {
  22333.             $this->ui->outputData("Logged in.", $command);
  22334.             $this->config->store();
  22335.         } else {
  22336.             return $this->raiseError("Login failed!");
  22337.         }
  22338.         return true;
  22339.     }
  22340.  
  22341.     // }}}
  22342.     // {{{ doLogout()
  22343.  
  22344.     /**
  22345.      * Execute the 'logout' command.
  22346.      *
  22347.      * @param string $command command name
  22348.      *
  22349.      * @param array $options option_name => value
  22350.      *
  22351.      * @param array $params list of additional parameters
  22352.      *
  22353.      * @return bool TRUE on success or
  22354.      * a PEAR error on failure
  22355.      *
  22356.      * @access public
  22357.      */
  22358.     function doLogout($command, $options, $params)
  22359.     {
  22360.         $reg = &$this->config->getRegistry();
  22361.         $channel = $this->config->get('default_channel');
  22362.         $chan = $reg->getChannel($channel);
  22363.         if (PEAR::isError($chan)) {
  22364.             return $this->raiseError($chan);
  22365.         }
  22366.         $server = $this->config->get('preferred_mirror');
  22367.         $this->ui->outputData("Logging out from $server.", $command);
  22368.         $this->config->remove('username');
  22369.         $this->config->remove('password');
  22370.         $this->config->store();
  22371.         return true;
  22372.     }
  22373.  
  22374.     // }}}
  22375. }
  22376.  
  22377. ?>PEAR-1.4.11/PEAR/Command/Build.xml100644   1750   1750         404 10470570063  11415 <commands version="1.0">
  22378.  <build>
  22379.   <summary>Build an Extension From C Source</summary>
  22380.   <function>doBuild</function>
  22381.   <shortcut>b</shortcut>
  22382.   <options />
  22383.   <doc>[package.xml]
  22384. Builds one or more extensions contained in a package.</doc>
  22385.  </build>
  22386. </commands>PEAR-1.4.11/PEAR/Command/Build.php100644   1750   1750        5431 10470570063  11431 <?php
  22387. /**
  22388.  * PEAR_Command_Auth (build command)
  22389.  *
  22390.  * PHP versions 4 and 5
  22391.  *
  22392.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  22393.  * that is available through the world-wide-web at the following URI:
  22394.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  22395.  * the PHP License and are unable to obtain it through the web, please
  22396.  * send a note to license@php.net so we can mail you a copy immediately.
  22397.  *
  22398.  * @category   pear
  22399.  * @package    PEAR
  22400.  * @author     Stig Bakken <ssb@php.net>
  22401.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  22402.  * @author     Greg Beaver <cellog@php.net>
  22403.  * @copyright  1997-2006 The PHP Group
  22404.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22405.  * @version    CVS: $Id: Build.php,v 1.13 2006/01/06 04:47:36 cellog Exp $
  22406.  * @link       http://pear.php.net/package/PEAR
  22407.  * @since      File available since Release 0.1
  22408.  */
  22409.  
  22410. /**
  22411.  * base class
  22412.  */
  22413. require_once 'PEAR/Command/Common.php';
  22414.  
  22415. /**
  22416.  * PEAR commands for building extensions.
  22417.  *
  22418.  * @category   pear
  22419.  * @package    PEAR
  22420.  * @author     Stig Bakken <ssb@php.net>
  22421.  * @author     Tomas V.V.Cox <cox@idecnet.com>
  22422.  * @author     Greg Beaver <cellog@php.net>
  22423.  * @copyright  1997-2006 The PHP Group
  22424.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22425.  * @version    Release: 1.4.11
  22426.  * @link       http://pear.php.net/package/PEAR
  22427.  * @since      Class available since Release 0.1
  22428.  */
  22429. class PEAR_Command_Build extends PEAR_Command_Common
  22430. {
  22431.     // {{{ properties
  22432.  
  22433.     var $commands = array(
  22434.         'build' => array(
  22435.             'summary' => 'Build an Extension From C Source',
  22436.             'function' => 'doBuild',
  22437.             'shortcut' => 'b',
  22438.             'options' => array(),
  22439.             'doc' => '[package.xml]
  22440. Builds one or more extensions contained in a package.'
  22441.             ),
  22442.         );
  22443.  
  22444.     // }}}
  22445.  
  22446.     // {{{ constructor
  22447.  
  22448.     /**
  22449.      * PEAR_Command_Build constructor.
  22450.      *
  22451.      * @access public
  22452.      */
  22453.     function PEAR_Command_Build(&$ui, &$config)
  22454.     {
  22455.         parent::PEAR_Command_Common($ui, $config);
  22456.     }
  22457.  
  22458.     // }}}
  22459.  
  22460.     // {{{ doBuild()
  22461.  
  22462.     function doBuild($command, $options, $params)
  22463.     {
  22464.         require_once 'PEAR/Builder.php';
  22465.         if (sizeof($params) < 1) {
  22466.             $params[0] = 'package.xml';
  22467.         }
  22468.         $builder = &new PEAR_Builder($this->ui);
  22469.         $this->debug = $this->config->get('verbose');
  22470.         $err = $builder->build($params[0], array(&$this, 'buildCallback'));
  22471.         if (PEAR::isError($err)) {
  22472.             return $err;
  22473.         }
  22474.         return true;
  22475.     }
  22476.  
  22477.     // }}}
  22478.     // {{{ buildCallback()
  22479.  
  22480.     function buildCallback($what, $data)
  22481.     {
  22482.         if (($what == 'cmdoutput' && $this->debug > 1) ||
  22483.             ($what == 'output' && $this->debug > 0)) {
  22484.             $this->ui->outputData(rtrim($data), 'build');
  22485.         }
  22486.     }
  22487.  
  22488.     // }}}
  22489. }
  22490. PEAR-1.4.11/PEAR/Command/Channels.xml100644   1750   1750        5230 10470570063  12133 <commands version="1.0">
  22491.  <list-channels>
  22492.   <summary>List Available Channels</summary>
  22493.   <function>doList</function>
  22494.   <shortcut>lc</shortcut>
  22495.   <options />
  22496.   <doc>
  22497. List all available channels for installation.
  22498. </doc>
  22499.  </list-channels>
  22500.  <update-channels>
  22501.   <summary>Update the Channel List</summary>
  22502.   <function>doUpdateAll</function>
  22503.   <shortcut>uc</shortcut>
  22504.   <options />
  22505.   <doc>
  22506. List all installed packages in all channels.
  22507. </doc>
  22508.  </update-channels>
  22509.  <channel-delete>
  22510.   <summary>Remove a Channel From the List</summary>
  22511.   <function>doDelete</function>
  22512.   <shortcut>cde</shortcut>
  22513.   <options />
  22514.   <doc><channel name>
  22515. Delete a channel from the registry.  You may not
  22516. remove any channel that has installed packages.
  22517. </doc>
  22518.  </channel-delete>
  22519.  <channel-add>
  22520.   <summary>Add a Channel</summary>
  22521.   <function>doAdd</function>
  22522.   <shortcut>ca</shortcut>
  22523.   <options />
  22524.   <doc><channel.xml>
  22525. Add a private channel to the channel list.  Note that all
  22526. public channels should be synced using "update-channels".
  22527. Parameter may be either a local file or remote URL to a
  22528. channel.xml.
  22529. </doc>
  22530.  </channel-add>
  22531.  <channel-update>
  22532.   <summary>Update an Existing Channel</summary>
  22533.   <function>doUpdate</function>
  22534.   <shortcut>cu</shortcut>
  22535.   <options>
  22536.    <force>
  22537.     <shortopt>f</shortopt>
  22538.     <doc>will force download of new channel.xml if an existing channel name is used</doc>
  22539.    </force>
  22540.    <channel>
  22541.     <shortopt>c</shortopt>
  22542.     <arg>CHANNEL</arg>
  22543.     <doc>will force download of new channel.xml if an existing channel name is used</doc>
  22544.    </channel>
  22545.   </options>
  22546.   <doc>[<channel.xml>|<channel name>]
  22547. Update a channel in the channel list directly.  Note that all
  22548. public channels can be synced using "update-channels".
  22549. Parameter may be a local or remote channel.xml, or the name of
  22550. an existing channel.
  22551. </doc>
  22552.  </channel-update>
  22553.  <channel-info>
  22554.   <summary>Retrieve Information on a Channel</summary>
  22555.   <function>doInfo</function>
  22556.   <shortcut>ci</shortcut>
  22557.   <options />
  22558.   <doc><package>
  22559. List the files in an installed package.
  22560. </doc>
  22561.  </channel-info>
  22562.  <channel-alias>
  22563.   <summary>Specify an alias to a channel name</summary>
  22564.   <function>doAlias</function>
  22565.   <shortcut>cha</shortcut>
  22566.   <options />
  22567.   <doc><channel> <alias>
  22568. Specify a specific alias to use for a channel name.
  22569. The alias may not be an existing channel name or
  22570. alias.
  22571. </doc>
  22572.  </channel-alias>
  22573.  <channel-discover>
  22574.   <summary>Initialize a Channel from its server</summary>
  22575.   <function>doDiscover</function>
  22576.   <shortcut>di</shortcut>
  22577.   <options />
  22578.   <doc>[<channel.xml>|<channel name>]
  22579. Initialize a Channel from its server and create the local channel.xml.
  22580. </doc>
  22581.  </channel-discover>
  22582. </commands>
  22583. PEAR-1.4.11/PEAR/Command/Channels.php100644   1750   1750      100100 10470570063  12152 <?php
  22584. // /* vim: set expandtab tabstop=4 shiftwidth=4: */
  22585. /**
  22586.  * PEAR_Command_Channels (list-channels, update-channels, channel-delete, channel-add,
  22587.  * channel-update, channel-info, channel-alias, channel-discover commands)
  22588.  *
  22589.  * PHP versions 4 and 5
  22590.  *
  22591.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  22592.  * that is available through the world-wide-web at the following URI:
  22593.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  22594.  * the PHP License and are unable to obtain it through the web, please
  22595.  * send a note to license@php.net so we can mail you a copy immediately.
  22596.  *
  22597.  * @category   pear
  22598.  * @package    PEAR
  22599.  * @author     Stig Bakken <ssb@php.net>
  22600.  * @author     Greg Beaver <cellog@php.net>
  22601.  * @copyright  1997-2006 The PHP Group
  22602.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22603.  * @version    CVS: $Id: Channels.php,v 1.44.2.1 2006/07/17 18:24:10 pajoye Exp $
  22604.  * @link       http://pear.php.net/package/PEAR
  22605.  * @since      File available since Release 1.4.0a1
  22606.  */
  22607.  
  22608. /**
  22609.  * base class
  22610.  */
  22611. require_once 'PEAR/Command/Common.php';
  22612.  
  22613. /**
  22614.  * PEAR commands for managing channels.
  22615.  *
  22616.  * @category   pear
  22617.  * @package    PEAR
  22618.  * @author     Greg Beaver <cellog@php.net>
  22619.  * @copyright  1997-2006 The PHP Group
  22620.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  22621.  * @version    Release: 1.4.11
  22622.  * @link       http://pear.php.net/package/PEAR
  22623.  * @since      Class available since Release 1.4.0a1
  22624.  */
  22625. class PEAR_Command_Channels extends PEAR_Command_Common
  22626. {
  22627.     // {{{ properties
  22628.  
  22629.     var $commands = array(
  22630.         'list-channels' => array(
  22631.             'summary' => 'List Available Channels',
  22632.             'function' => 'doList',
  22633.             'shortcut' => 'lc',
  22634.             'options' => array(),
  22635.             'doc' => '
  22636. List all available channels for installation.
  22637. ',
  22638.             ),
  22639.         'update-channels' => array(
  22640.             'summary' => 'Update the Channel List',
  22641.             'function' => 'doUpdateAll',
  22642.             'shortcut' => 'uc',
  22643.             'options' => array(),
  22644.             'doc' => '
  22645. List all installed packages in all channels.
  22646. '
  22647.             ),
  22648.         'channel-delete' => array(
  22649.             'summary' => 'Remove a Channel From the List',
  22650.             'function' => 'doDelete',
  22651.             'shortcut' => 'cde',
  22652.             'options' => array(),
  22653.             'doc' => '<channel name>
  22654. Delete a channel from the registry.  You may not
  22655. remove any channel that has installed packages.
  22656. '
  22657.             ),
  22658.         'channel-add' => array(
  22659.             'summary' => 'Add a Channel',
  22660.             'function' => 'doAdd',
  22661.             'shortcut' => 'ca',
  22662.             'options' => array(),
  22663.             'doc' => '<channel.xml>
  22664. Add a private channel to the channel list.  Note that all
  22665. public channels should be synced using "update-channels".
  22666. Parameter may be either a local file or remote URL to a
  22667. channel.xml.
  22668. '
  22669.             ),
  22670.         'channel-update' => array(
  22671.             'summary' => 'Update an Existing Channel',
  22672.             'function' => 'doUpdate',
  22673.             'shortcut' => 'cu',
  22674.             'options' => array(
  22675.                 'force' => array(
  22676.                     'shortopt' => 'f',
  22677.                     'doc' => 'will force download of new channel.xml if an existing channel name is used',
  22678.                     ),
  22679.                 'channel' => array(
  22680.                     'shortopt' => 'c',
  22681.                     'arg' => 'CHANNEL',
  22682.                     'doc' => 'will force download of new channel.xml if an existing channel name is used',
  22683.                     ),
  22684. ),
  22685.             'doc' => '[<channel.xml>|<channel name>]
  22686. Update a channel in the channel list directly.  Note that all
  22687. public channels can be synced using "update-channels".
  22688. Parameter may be a local or remote channel.xml, or the name of
  22689. an existing channel.
  22690. '
  22691.             ),
  22692.         'channel-info' => array(
  22693.             'summary' => 'Retrieve Information on a Channel',
  22694.             'function' => 'doInfo',
  22695.             'shortcut' => 'ci',
  22696.             'options' => array(),
  22697.             'doc' => '<package>
  22698. List the files in an installed package.
  22699. '
  22700.             ),
  22701.         'channel-alias' => array(
  22702.             'summary' => 'Specify an alias to a channel name',
  22703.             'function' => 'doAlias',
  22704.             'shortcut' => 'cha',
  22705.             'options' => array(),
  22706.             'doc' => '<channel> <alias>
  22707. Specify a specific alias to use for a channel name.
  22708. The alias may not be an existing channel name or
  22709. alias.
  22710. '
  22711.             ),
  22712.         'channel-discover' => array(
  22713.             'summary' => 'Initialize a Channel from its server',
  22714.             'function' => 'doDiscover',
  22715.             'shortcut' => 'di',
  22716.             'options' => array(),
  22717.             'doc' => '[<channel.xml>|<channel name>]
  22718. Initialize a Channel from its server and creates the local channel.xml.
  22719. '
  22720.             ),
  22721.         );
  22722.  
  22723.     // }}}
  22724.     // {{{ constructor
  22725.  
  22726.     /**
  22727.      * PEAR_Command_Registry constructor.
  22728.      *
  22729.      * @access public
  22730.      */
  22731.     function PEAR_Command_Channels(&$ui, &$config)
  22732.     {
  22733.         parent::PEAR_Command_Common($ui, $config);
  22734.     }
  22735.  
  22736.     // }}}
  22737.  
  22738.     // {{{ doList()
  22739.     
  22740.     function _sortChannels($a, $b)
  22741.     {
  22742.         return strnatcasecmp($a->getName(), $b->getName());
  22743.     }
  22744.  
  22745.     function doList($command, $options, $params)
  22746.     {
  22747.         $reg = &$this->config->getRegistry();
  22748.         $registered = $reg->getChannels();
  22749.         usort($registered, array(&$this, '_sortchannels'));
  22750.         $i = $j = 0;
  22751.         $data = array(
  22752.             'caption' => 'Registered Channels:',
  22753.             'border' => true,
  22754.             'headline' => array('Channel', 'Summary')
  22755.             );
  22756.         foreach ($registered as $channel) {
  22757.             $data['data'][] = array($channel->getName(),
  22758.                                       $channel->getSummary());
  22759.         }
  22760.         if (count($registered)==0) {
  22761.             $data = '(no registered channels)';
  22762.         }
  22763.         $this->ui->outputData($data, $command);
  22764.         return true;
  22765.     }
  22766.     
  22767.     function doUpdateAll($command, $options, $params)
  22768.     {
  22769.         $reg = &$this->config->getRegistry();
  22770.         $savechannel = $this->config->get('default_channel');
  22771.         if (isset($options['channel'])) {
  22772.             if (!$reg->channelExists($options['channel'])) {
  22773.                 return $this->raiseError('Unknown channel "' . $options['channel'] . '"');
  22774.             }
  22775.             $this->config->set('default_channel', $options['channel']);
  22776.         } else {
  22777.             $this->config->set('default_channel', 'pear.php.net');
  22778.         }
  22779.         $remote = &$this->config->getRemote();
  22780.         $channels = $remote->call('channel.listAll');
  22781.         if (PEAR::isError($channels)) {
  22782.             $this->config->set('default_channel', $savechannel);
  22783.             return $channels;
  22784.         }
  22785.         if (!is_array($channels) || isset($channels['faultCode'])) {
  22786.             $this->config->set('default_channel', $savechannel);
  22787.             return $this->raiseError("Incorrect channel listing returned from channel '$chan'");
  22788.         }
  22789.         if (!count($channels)) {
  22790.             $data = 'no updates available';
  22791.         }
  22792.         $dl = &$this->getDownloader();
  22793.         if (!class_exists('System')) {
  22794.             require_once 'System.php';
  22795.         }
  22796.         $tmpdir = System::mktemp(array('-d'));
  22797.         foreach ($channels as $channel) {
  22798.             $channel = $channel[0];
  22799.             $save = $channel;
  22800.             if ($reg->channelExists($channel, true)) {
  22801.                 $this->ui->outputData("Updating channel \"$channel\"", $command);
  22802.                 $test = $reg->getChannel($channel, true);
  22803.                 if (PEAR::isError($test)) {
  22804.                     $this->ui->outputData("Channel '$channel' is corrupt in registry!", $command);
  22805.                     $lastmodified = false;
  22806.                 } else {
  22807.                     $lastmodified = $test->lastModified();
  22808.                     
  22809.                 }
  22810.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  22811.                 $contents = $dl->downloadHttp('http://' . $test->getName() . '/channel.xml',
  22812.                     $this->ui, $tmpdir, null, $lastmodified);
  22813.                 PEAR::staticPopErrorHandling();
  22814.                 if (PEAR::isError($contents)) {
  22815.                     $this->ui->outputData('ERROR: Cannot retrieve channel.xml for channel "' .
  22816.                         $test->getName() . '"', $command);
  22817.                     continue;
  22818.                 }
  22819.                 if (!$contents) {
  22820.                     $this->ui->outputData("Channel \"$channel\" is up-to-date", $command);
  22821.                     continue;
  22822.                 }
  22823.                 list($contents, $lastmodified) = $contents;
  22824.                 $info = implode('', file($contents));
  22825.                 if (!$info) {
  22826.                     $this->ui->outputData("Channel \"$channel\" is up-to-date", $command);
  22827.                     continue;
  22828.                 }
  22829.                 if (!class_exists('PEAR_ChannelFile')) {
  22830.                     require_once 'PEAR/ChannelFile.php';
  22831.                 }
  22832.                 $channelinfo = new PEAR_ChannelFile;
  22833.                 $channelinfo->fromXmlString($info);
  22834.                 if ($channelinfo->getErrors()) {
  22835.                     $this->ui->outputData("Downloaded channel data from channel \"$channel\" " . 
  22836.                         'is corrupt, skipping', $command);
  22837.                     continue;
  22838.                 }
  22839.                 $channel = $channelinfo;
  22840.                 if ($channel->getName() != $save) {
  22841.                     $this->ui->outputData('ERROR: Security risk - downloaded channel ' .
  22842.                         'definition file for channel "'
  22843.                         . $channel->getName() . ' from channel "' . $save .
  22844.                         '".  To use anyway, use channel-update', $command);
  22845.                     continue;
  22846.                 }
  22847.                 $reg->updateChannel($channel, $lastmodified);
  22848.             } else {
  22849.                 if ($reg->isAlias($channel)) {
  22850.                     $temp = &$reg->getChannel($channel);
  22851.                     if (PEAR::isError($temp)) {
  22852.                         return $this->raiseError($temp);
  22853.                     }
  22854.                     $temp->setAlias($temp->getName(), true); // set the alias to the channel name
  22855.                     if ($reg->channelExists($temp->getName())) {
  22856.                         $this->ui->outputData('ERROR: existing channel "' . $temp->getName() .
  22857.                             '" is aliased to "' . $channel . '" already and cannot be ' .
  22858.                             're-aliased to "' . $temp->getName() . '" because a channel with ' .
  22859.                             'that name or alias already exists!  Please re-alias and try ' .
  22860.                             'again.', $command);
  22861.                         continue;
  22862.                     }
  22863.                 }
  22864.                 $this->ui->outputData("Adding new channel \"$channel\"", $command);
  22865.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  22866.                 $contents = $dl->downloadHttp('http://' . $channel . '/channel.xml',
  22867.                     $this->ui, $tmpdir, null, false);
  22868.                 PEAR::staticPopErrorHandling();
  22869.                 if (PEAR::isError($contents)) {
  22870.                     $this->ui->outputData('ERROR: Cannot retrieve channel.xml for channel "' .
  22871.                         $channel . '"', $command);
  22872.                     continue;
  22873.                 }
  22874.                 list($contents, $lastmodified) = $contents;
  22875.                 $info = implode('', file($contents));
  22876.                 if (!class_exists('PEAR_ChannelFile')) {
  22877.                     require_once 'PEAR/ChannelFile.php';
  22878.                 }
  22879.                 $channelinfo = new PEAR_Channelfile;
  22880.                 $channelinfo->fromXmlString($info);
  22881.                 if ($channelinfo->getErrors()) {
  22882.                     $this->ui->outputData("Downloaded channel data from channel \"$channel\"" .
  22883.                         ' is corrupt, skipping', $command);
  22884.                     continue;
  22885.                 }
  22886.                 $channel = $channelinfo;
  22887.                 if ($channel->getName() != $save) {
  22888.                     $this->ui->outputData('ERROR: Security risk - downloaded channel ' .
  22889.                         'definition file for channel "'
  22890.                         . $channel->getName() . '" from channel "' . $save .
  22891.                         '".  To use anyway, use channel-update', $command);
  22892.                     continue;
  22893.                 }
  22894.                 $reg->addChannel($channel, $lastmodified);
  22895.             }
  22896.         }
  22897.         $this->config->set('default_channel', $savechannel);
  22898.         $this->ui->outputData('update-channels complete', $command);
  22899.         return true;
  22900.     }
  22901.     
  22902.     function doInfo($command, $options, $params)
  22903.     {
  22904.         if (sizeof($params) != 1) {
  22905.             return $this->raiseError("No channel specified");
  22906.         }
  22907.         $reg = &$this->config->getRegistry();
  22908.         $channel = strtolower($params[0]);
  22909.         if ($reg->channelExists($channel)) {
  22910.             $chan = $reg->getChannel($channel);
  22911.             if (PEAR::isError($chan)) {
  22912.                 return $this->raiseError($chan);
  22913.             }
  22914.         } else {
  22915.             if (strpos($channel, '://')) {
  22916.                 $downloader = &$this->getDownloader();
  22917.                 if (!class_exists('System')) {
  22918.                     require_once 'System.php';
  22919.                 }
  22920.                 $tmpdir = System::mktemp(array('-d'));
  22921.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  22922.                 $loc = $downloader->downloadHttp($channel, $this->ui, $tmpdir);
  22923.                 PEAR::staticPopErrorHandling();
  22924.                 if (PEAR::isError($loc)) {
  22925.                     return $this->raiseError('Cannot open "' . $channel . '"');
  22926.                 } else {
  22927.                     $contents = implode('', file($loc));
  22928.                 }
  22929.             } else {
  22930.                 $fp = @fopen($params[0], 'r');
  22931.                 if (!$fp) {
  22932.                     if (@file_exists($params[0])) {
  22933.                         return $this->raiseError('Cannot open "' . $params[0] . '"');
  22934.                     } else {
  22935.                         return $this->raiseError('Unknown channel "' . $channel . '"');
  22936.                     }
  22937.                 }
  22938.                 $contents = '';
  22939.                 while (!feof($fp)) {
  22940.                     $contents .= fread($fp, 1024);
  22941.                 }
  22942.                 fclose($fp);
  22943.             }
  22944.             if (!class_exists('PEAR_ChannelFile')) {
  22945.                 require_once 'PEAR/ChannelFile.php';
  22946.             }
  22947.             $chan = new PEAR_ChannelFile;
  22948.             $chan->fromXmlString($contents);
  22949.             $chan->validate();
  22950.             if ($errs = $chan->getErrors(true)) {
  22951.                 foreach ($errs as $err) {
  22952.                     $this->ui->outputData($err['level'] . ': ' . $err['message']);
  22953.                 }
  22954.                 return $this->raiseError('Channel file "' . $params[0] . '" is not valid');
  22955.             }
  22956.         }
  22957.         if ($chan) {
  22958.             $channel = $chan->getName();
  22959.             $caption = 'Channel ' . $channel . ' Information:';
  22960.             $data1 = array(
  22961.                 'caption' => $caption,
  22962.                 'border' => true);
  22963.             $data1['data']['server'] = array('Name and Server', $chan->getName());
  22964.             if ($chan->getAlias() != $chan->getName()) {
  22965.                 $data1['data']['alias'] = array('Alias', $chan->getAlias());
  22966.             }
  22967.             $data1['data']['summary'] = array('Summary', $chan->getSummary());
  22968.             $validate = $chan->getValidationPackage();
  22969.             $data1['data']['vpackage'] = array('Validation Package Name', $validate['_content']);
  22970.             $data1['data']['vpackageversion'] =
  22971.                 array('Validation Package Version', $validate['attribs']['version']);
  22972.             $d = array();
  22973.             $d['main'] = $data1;
  22974.  
  22975.             $data['data'] = array();
  22976.             $data['caption'] = 'Server Capabilities';
  22977.             $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
  22978.             $capabilities = $chan->getFunctions('xmlrpc');
  22979.             $soaps = $chan->getFunctions('soap');
  22980.             if ($capabilities || $soaps || $chan->supportsREST()) {
  22981.                 if ($capabilities) {
  22982.                     if (!isset($capabilities[0])) {
  22983.                         $capabilities = array($capabilities);
  22984.                     }
  22985.                     foreach ($capabilities as $protocol) {
  22986.                         $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
  22987.                             $protocol['_content']);
  22988.                     }
  22989.                 }
  22990.                 if ($soaps) {
  22991.                     if (!isset($soaps[0])) {
  22992.                         $soaps = array($soaps);
  22993.                     }
  22994.                     foreach ($soaps as $protocol) {
  22995.                         $data['data'][] = array('soap', $protocol['attribs']['version'],
  22996.                             $protocol['_content']);
  22997.                     }
  22998.                 }
  22999.                 if ($chan->supportsREST()) {
  23000.                     $funcs = $chan->getFunctions('rest');
  23001.                     if (!isset($funcs[0])) {
  23002.                         $funcs = array($funcs);
  23003.                     }
  23004.                     foreach ($funcs as $protocol) {
  23005.                         $data['data'][] = array('rest', $protocol['attribs']['type'],
  23006.                             $protocol['_content']); 
  23007.                     }
  23008.                 }
  23009.             } else {
  23010.                 $data['data'][] = array('No supported protocols');
  23011.             }
  23012.             $d['protocols'] = $data;
  23013.             $data['data'] = array();
  23014.             $mirrors = $chan->getMirrors();
  23015.             if ($mirrors) {
  23016.                 $data['caption'] = 'Channel ' . $channel . ' Mirrors:';
  23017.                 unset($data['headline']);
  23018.                 foreach ($mirrors as $mirror) {
  23019.                     $data['data'][] = array($mirror['attribs']['host']);
  23020.                     $d['mirrors'] = $data;
  23021.                 }
  23022.                 foreach ($mirrors as $mirror) {
  23023.                     $data['data'] = array();
  23024.                     $data['caption'] = 'Mirror ' . $mirror['attribs']['host'] . ' Capabilities';
  23025.                     $data['headline'] = array('Type', 'Version/REST type', 'Function Name/REST base');
  23026.                     $capabilities = $chan->getFunctions('xmlrpc', $mirror['attribs']['host']);
  23027.                     $soaps = $chan->getFunctions('soap', $mirror['attribs']['host']);
  23028.                     if ($capabilities || $soaps || $chan->supportsREST($mirror['attribs']['host'])) {
  23029.                         if ($capabilities) {
  23030.                             if (!isset($capabilities[0])) {
  23031.                                 $capabilities = array($capabilities);
  23032.                             }
  23033.                             foreach ($capabilities as $protocol) {
  23034.                                 $data['data'][] = array('xmlrpc', $protocol['attribs']['version'],
  23035.                                     $protocol['_content']);
  23036.                             }
  23037.                         }
  23038.                         if ($soaps) {
  23039.                             if (!isset($soaps[0])) {
  23040.                                 $soaps = array($soaps);
  23041.                             }
  23042.                             foreach ($soaps as $protocol) {
  23043.                                 $data['data'][] = array('soap', $protocol['attribs']['version'],
  23044.                                     $protocol['_content']);
  23045.                             }
  23046.                         }
  23047.                         if ($chan->supportsREST($mirror['attribs']['host'])) {
  23048.                             $funcs = $chan->getFunctions('rest', $mirror['attribs']['host']);
  23049.                             if (!isset($funcs[0])) {
  23050.                                 $funcs = array($funcs);
  23051.                             }
  23052.                             foreach ($funcs as $protocol) {
  23053.                                 $data['data'][] = array('rest', $protocol['attribs']['type'],
  23054.                                     $protocol['_content']); 
  23055.                             }
  23056.                         }
  23057.                     } else {
  23058.                         $data['data'][] = array('No supported protocols');
  23059.                     }
  23060.                     $d['mirrorprotocols'] = $data;
  23061.                 }
  23062.             }
  23063.             $this->ui->outputData($d, 'channel-info');
  23064.         } else {
  23065.             return $this->raiseError('Serious error: Channel "' . $params[0] .
  23066.                 '" has a corrupted registry entry');
  23067.         }
  23068.     }
  23069.  
  23070.     // }}}
  23071.     
  23072.     function doDelete($command, $options, $params)
  23073.     {
  23074.         if (sizeof($params) != 1) {
  23075.             return $this->raiseError('channel-delete: no channel specified');
  23076.         }
  23077.         $reg = &$this->config->getRegistry();
  23078.         if (!$reg->channelExists($params[0])) {
  23079.             return $this->raiseError('channel-delete: channel "' . $params[0] . '" does not exist');
  23080.         }
  23081.         $channel = $reg->channelName($params[0]);
  23082.         if ($channel == 'pear.php.net') {
  23083.             return $this->raiseError('Cannot delete the pear.php.net channel');
  23084.         }
  23085.         if ($channel == 'pecl.php.net') {
  23086.             return $this->raiseError('Cannot delete the pecl.php.net channel');
  23087.         }
  23088.         if ($channel == '__uri') {
  23089.             return $this->raiseError('Cannot delete the __uri pseudo-channel');
  23090.         }
  23091.         if (PEAR::isError($err = $reg->listPackages($channel))) {
  23092.             return $err;
  23093.         }
  23094.         if (count($err)) {
  23095.             return $this->raiseError('Channel "' . $channel .
  23096.                 '" has installed packages, cannot delete');
  23097.         }
  23098.         if (!$reg->deleteChannel($channel)) {
  23099.             return $this->raiseError('Channel "' . $channel . '" deletion failed');
  23100.         } else {
  23101.             $this->config->deleteChannel($channel);
  23102.             $this->ui->outputData('Channel "' . $channel . '" deleted', $command);
  23103.         }
  23104.     }
  23105.  
  23106.     function doAdd($command, $options, $params)
  23107.     {
  23108.         if (sizeof($params) != 1) {
  23109.             return $this->raiseError('channel-add: no channel file specified');
  23110.         }
  23111.         if (strpos($params[0], '://')) {
  23112.             $downloader = &$this->getDownloader();
  23113.             if (!class_exists('System')) {
  23114.                 require_once 'System.php';
  23115.             }
  23116.             $tmpdir = System::mktemp(array('-d'));
  23117.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  23118.             $loc = $downloader->downloadHttp($params[0], $this->ui, $tmpdir, null, false);
  23119.             PEAR::staticPopErrorHandling();
  23120.             if (PEAR::isError($loc)) {
  23121.                 return $this->raiseError('channel-add: Cannot open "' . $params[0] . '"');
  23122.             } else {
  23123.                 list($loc, $lastmodified) = $loc;
  23124.                 $contents = implode('', file($loc));
  23125.             }
  23126.         } else {
  23127.             $lastmodified = false;
  23128.             $fp = @fopen($params[0], 'r');
  23129.             if (!$fp) {
  23130.                 return $this->raiseError('channel-add: cannot open "' . $params[0] . '"');
  23131.             }
  23132.             $contents = '';
  23133.             while (!feof($fp)) {
  23134.                 $contents .= fread($fp, 1024);
  23135.             }
  23136.             fclose($fp);
  23137.         }
  23138.         if (!class_exists('PEAR_ChannelFile')) {
  23139.             require_once 'PEAR/ChannelFile.php';
  23140.         }
  23141.         $channel = new PEAR_ChannelFile;
  23142.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  23143.         $result = $channel->fromXmlString($contents);
  23144.         PEAR::staticPopErrorHandling();
  23145.         if (!$result) {
  23146.             $exit = false;
  23147.             if (count($errors = $channel->getErrors(true))) {
  23148.                 foreach ($errors as $error) {
  23149.                     $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
  23150.                     if (!$exit) {
  23151.                         $exit = $error['level'] == 'error' ? true : false;
  23152.                     }
  23153.                 }
  23154.                 if ($exit) {
  23155.                     return $this->raiseError('channel-add: invalid channel.xml file');
  23156.                 }
  23157.             }
  23158.         }
  23159.         $reg = &$this->config->getRegistry();
  23160.         if ($reg->channelExists($channel->getName())) {
  23161.             return $this->raiseError('channel-add: Channel "' . $channel->getName() .
  23162.                 '" exists, use channel-update to update entry');
  23163.         }
  23164.         $ret = $reg->addChannel($channel, $lastmodified);
  23165.         if (PEAR::isError($ret)) {
  23166.             return $ret;
  23167.         }
  23168.         if (!$ret) {
  23169.             return $this->raiseError('channel-add: adding Channel "' . $channel->getName() .
  23170.                 '" to registry failed');
  23171.         }
  23172.         $this->config->setChannels($reg->listChannels());
  23173.         $this->config->writeConfigFile();
  23174.         $this->ui->outputData('Adding Channel "' . $channel->getName() . '" succeeded', $command);
  23175.     }
  23176.  
  23177.     function doUpdate($command, $options, $params)
  23178.     {
  23179.         if (!class_exists('System')) {
  23180.             require_once 'System.php';
  23181.         }
  23182.         $tmpdir = System::mktemp(array('-d'));
  23183.         $reg = &$this->config->getRegistry();
  23184.         if (sizeof($params) != 1) {
  23185.             return $this->raiseError("No channel file specified");
  23186.         }
  23187.         $lastmodified = false;
  23188.         if ((!file_exists($params[0]) || is_dir($params[0]))
  23189.               && $reg->channelExists(strtolower($params[0]))) {
  23190.             $c = $reg->getChannel(strtolower($params[0]));
  23191.             if (PEAR::isError($c)) {
  23192.                 return $this->raiseError($c);
  23193.             }
  23194.             $this->ui->outputData('Retrieving channel.xml from remote server');
  23195.             $dl = &$this->getDownloader(array());
  23196.             // if force is specified, use a timestamp of "1" to force retrieval
  23197.             $lastmodified = isset($options['force']) ? false : $c->lastModified();
  23198.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  23199.             $contents = $dl->downloadHttp('http://' . $c->getName() . '/channel.xml',
  23200.                 $this->ui, $tmpdir, null, $lastmodified);
  23201.             PEAR::staticPopErrorHandling();
  23202.             if (PEAR::isError($contents)) {
  23203.                 return $this->raiseError('Cannot retrieve channel.xml for channel "' .
  23204.                     $c->getName() . '"');
  23205.             }
  23206.             list($contents, $lastmodified) = $contents;
  23207.             if (!$contents) {
  23208.                 $this->ui->outputData("Channel $params[0] channel.xml is up to date");
  23209.                 return;
  23210.             }
  23211.             $contents = implode('', file($contents));
  23212.             if (!class_exists('PEAR_ChannelFile')) {
  23213.                 require_once 'PEAR/ChannelFile.php';
  23214.             }
  23215.             $channel = new PEAR_ChannelFile;
  23216.             $channel->fromXmlString($contents);
  23217.             if (!$channel->getErrors()) {
  23218.                 // security check: is the downloaded file for the channel we got it from?
  23219.                 if (strtolower($channel->getName()) != strtolower($c->getName())) {
  23220.                     if (isset($options['force'])) {
  23221.                         $this->ui->log(0, 'WARNING: downloaded channel definition file' .
  23222.                             ' for channel "' . $channel->getName() . '" from channel "' .
  23223.                             strtolower($c->getName()) . '"');
  23224.                     } else {
  23225.                         return $this->raiseError('ERROR: downloaded channel definition file' .
  23226.                             ' for channel "' . $channel->getName() . '" from channel "' .
  23227.                             strtolower($c->getName()) . '"');
  23228.                     }
  23229.                 }
  23230.             }
  23231.         } else {
  23232.             if (strpos($params[0], '://')) {
  23233.                 $dl = &$this->getDownloader();
  23234.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  23235.                 $loc = $dl->downloadHttp($params[0],
  23236.                     $this->ui, $tmpdir, null, $lastmodified);
  23237.                 PEAR::staticPopErrorHandling();
  23238.                 if (PEAR::isError($loc)) {
  23239.                     return $this->raiseError("Cannot open " . $params[0]);
  23240.                 } else {
  23241.                     list($loc, $lastmodified) = $loc;
  23242.                     $contents = implode('', file($loc));
  23243.                 }
  23244.             } else {
  23245.                 $fp = @fopen($params[0], 'r');
  23246.                 if (!$fp) {
  23247.                     return $this->raiseError("Cannot open " . $params[0]);
  23248.                 }
  23249.                 $contents = '';
  23250.                 while (!feof($fp)) {
  23251.                     $contents .= fread($fp, 1024);
  23252.                 }
  23253.                 fclose($fp);
  23254.             }
  23255.             if (!class_exists('PEAR_ChannelFile')) {
  23256.                 require_once 'PEAR/ChannelFile.php';
  23257.             }
  23258.             $channel = new PEAR_ChannelFile;
  23259.             $channel->fromXmlString($contents);
  23260.         }
  23261.         $exit = false;
  23262.         if (count($errors = $channel->getErrors(true))) {
  23263.             foreach ($errors as $error) {
  23264.                 $this->ui->outputData(ucfirst($error['level'] . ': ' . $error['message']));
  23265.                 if (!$exit) {
  23266.                     $exit = $error['level'] == 'error' ? true : false;
  23267.                 }
  23268.             }
  23269.             if ($exit) {
  23270.                 return $this->raiseError('Invalid channel.xml file');
  23271.             }
  23272.         }
  23273.         if (!$reg->channelExists($channel->getName())) {
  23274.             return $this->raiseError('Error: Channel "' . $channel->getName() .
  23275.                 '" does not exist, use channel-add to add an entry');
  23276.         }
  23277.         $ret = $reg->updateChannel($channel, $lastmodified);
  23278.         if (PEAR::isError($ret)) {
  23279.             return $ret;
  23280.         }
  23281.         if (!$ret) {
  23282.             return $this->raiseError('Updating Channel "' . $channel->getName() .
  23283.                 '" in registry failed');
  23284.         }
  23285.         $this->config->setChannels($reg->listChannels());
  23286.         $this->config->writeConfigFile();
  23287.         $this->ui->outputData('Update of Channel "' . $channel->getName() . '" succeeded');
  23288.     }
  23289.  
  23290.     function &getDownloader()
  23291.     {
  23292.         if (!class_exists('PEAR_Downloader')) {
  23293.             require_once 'PEAR/Downloader.php';
  23294.         }
  23295.         $a = new PEAR_Downloader($this->ui, array(), $this->config);
  23296.         return $a;
  23297.     }
  23298.  
  23299.     function doAlias($command, $options, $params)
  23300.     {
  23301.         $reg = &$this->config->getRegistry();
  23302.         if (sizeof($params) == 1) {
  23303.             return $this->raiseError('No channel alias specified');
  23304.         }
  23305.         if (sizeof($params) != 2) {
  23306.             return $this->raiseError(
  23307.                 'Invalid format, correct is: channel-alias channel alias');
  23308.         }
  23309.         if (!$reg->channelExists($params[0], true)) {
  23310.             if ($reg->isAlias($params[0])) {
  23311.                 $extra = ' (use "channel-alias ' . $reg->channelName($params[0]) . ' ' .
  23312.                     strtolower($params[1]) . '")';
  23313.             } else {
  23314.                 $extra = '';
  23315.             }
  23316.             return $this->raiseError('"' . $params[0] . '" is not a valid channel' . $extra);
  23317.         }
  23318.         if ($reg->isAlias($params[1])) {
  23319.             return $this->raiseError('Channel "' . $reg->channelName($params[1]) . '" is ' .
  23320.                 'already aliased to "' . strtolower($params[1]) . '", cannot re-alias');
  23321.         }
  23322.         $chan = &$reg->getChannel($params[0]);
  23323.         if (PEAR::isError($chan)) {
  23324.             return $this->raiseError('Corrupt registry?  Error retrieving channel "' . $params[0] .
  23325.                 '" information (' . $chan->getMessage() . ')');
  23326.         }
  23327.         // make it a local alias
  23328.         if (!$chan->setAlias(strtolower($params[1]), true)) {
  23329.             return $this->raiseError('Alias "' . strtolower($params[1]) .
  23330.                 '" is not a valid channel alias');
  23331.         }
  23332.         $reg->updateChannel($chan);
  23333.         $this->ui->outputData('Channel "' . $chan->getName() . '" aliased successfully to "' .
  23334.             strtolower($params[1]) . '"');
  23335.     }
  23336.  
  23337.     function doDiscover($command, $options, $params)
  23338.     {
  23339.         $reg = &$this->config->getRegistry();
  23340.         if (sizeof($params) != 1) {
  23341.             return $this->raiseError("No channel server specified");
  23342.         }
  23343.         if ($reg->channelExists($params[0])) {
  23344.             if ($reg->isAlias($params[0])) {
  23345.                 return $this->raiseError("A channel alias named \"$params[0]\" " .
  23346.                     'already exists, aliasing channel "' . $reg->channelName($params[0])
  23347.                     . '"');
  23348.             } else {
  23349.                 return $this->raiseError("Channel \"$params[0]\" is already initialized");
  23350.             }
  23351.         }
  23352.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  23353.         $err = $this->doAdd($command, $options, array('http://' . $params[0] . '/channel.xml'));
  23354.         $this->popErrorHandling();
  23355.         if (PEAR::isError($err)) {
  23356.             return $this->raiseError("Discovery of channel \"$params[0]\" failed (" .
  23357.                 $err->getMessage() . ')');
  23358.         }
  23359.         $this->ui->outputData("Discovery of channel \"$params[0]\" succeeded", $command);
  23360.     }
  23361. }
  23362. ?>
  23363. PEAR-1.4.11/PEAR/Command/Common.php100644   1750   1750       20443 10470570063  11642 <?php
  23364. /**
  23365.  * PEAR_Command_Common base class
  23366.  *
  23367.  * PHP versions 4 and 5
  23368.  *
  23369.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  23370.  * that is available through the world-wide-web at the following URI:
  23371.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  23372.  * the PHP License and are unable to obtain it through the web, please
  23373.  * send a note to license@php.net so we can mail you a copy immediately.
  23374.  *
  23375.  * @category   pear
  23376.  * @package    PEAR
  23377.  * @author     Stig Bakken <ssb@php.net>
  23378.  * @author     Greg Beaver <cellog@php.net>
  23379.  * @copyright  1997-2006 The PHP Group
  23380.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23381.  * @version    CVS: $Id: Common.php,v 1.32.2.1 2006/06/08 22:27:11 pajoye Exp $
  23382.  * @link       http://pear.php.net/package/PEAR
  23383.  * @since      File available since Release 0.1
  23384.  */
  23385.  
  23386. /**
  23387.  * base class
  23388.  */
  23389. require_once 'PEAR.php';
  23390.  
  23391. /**
  23392.  * PEAR commands base class
  23393.  *
  23394.  * @category   pear
  23395.  * @package    PEAR
  23396.  * @author     Stig Bakken <ssb@php.net>
  23397.  * @author     Greg Beaver <cellog@php.net>
  23398.  * @copyright  1997-2006 The PHP Group
  23399.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23400.  * @version    Release: 1.4.11
  23401.  * @link       http://pear.php.net/package/PEAR
  23402.  * @since      Class available since Release 0.1
  23403.  */
  23404. class PEAR_Command_Common extends PEAR
  23405. {
  23406.     // {{{ properties
  23407.  
  23408.     /**
  23409.      * PEAR_Config object used to pass user system and configuration
  23410.      * on when executing commands
  23411.      *
  23412.      * @var PEAR_Config
  23413.      */
  23414.     var $config;
  23415.     /**
  23416.      * @var PEAR_Registry
  23417.      * @access protected
  23418.      */
  23419.     var $_registry;
  23420.  
  23421.     /**
  23422.      * User Interface object, for all interaction with the user.
  23423.      * @var object
  23424.      */
  23425.     var $ui;
  23426.  
  23427.     var $_deps_rel_trans = array(
  23428.                                  'lt' => '<',
  23429.                                  'le' => '<=',
  23430.                                  'eq' => '=',
  23431.                                  'ne' => '!=',
  23432.                                  'gt' => '>',
  23433.                                  'ge' => '>=',
  23434.                                  'has' => '=='
  23435.                                  );
  23436.  
  23437.     var $_deps_type_trans = array(
  23438.                                   'pkg' => 'package',
  23439.                                   'ext' => 'extension',
  23440.                                   'php' => 'PHP',
  23441.                                   'prog' => 'external program',
  23442.                                   'ldlib' => 'external library for linking',
  23443.                                   'rtlib' => 'external runtime library',
  23444.                                   'os' => 'operating system',
  23445.                                   'websrv' => 'web server',
  23446.                                   'sapi' => 'SAPI backend'
  23447.                                   );
  23448.  
  23449.     // }}}
  23450.     // {{{ constructor
  23451.  
  23452.     /**
  23453.      * PEAR_Command_Common constructor.
  23454.      *
  23455.      * @access public
  23456.      */
  23457.     function PEAR_Command_Common(&$ui, &$config)
  23458.     {
  23459.         parent::PEAR();
  23460.         $this->config = &$config;
  23461.         $this->ui = &$ui;
  23462.     }
  23463.  
  23464.     // }}}
  23465.  
  23466.     // {{{ getCommands()
  23467.  
  23468.     /**
  23469.      * Return a list of all the commands defined by this class.
  23470.      * @return array list of commands
  23471.      * @access public
  23472.      */
  23473.     function getCommands()
  23474.     {
  23475.         $ret = array();
  23476.         foreach (array_keys($this->commands) as $command) {
  23477.             $ret[$command] = $this->commands[$command]['summary'];
  23478.         }
  23479.         return $ret;
  23480.     }
  23481.  
  23482.     // }}}
  23483.     // {{{ getShortcuts()
  23484.  
  23485.     /**
  23486.      * Return a list of all the command shortcuts defined by this class.
  23487.      * @return array shortcut => command
  23488.      * @access public
  23489.      */
  23490.     function getShortcuts()
  23491.     {
  23492.         $ret = array();
  23493.         foreach (array_keys($this->commands) as $command) {
  23494.             if (isset($this->commands[$command]['shortcut'])) {
  23495.                 $ret[$this->commands[$command]['shortcut']] = $command;
  23496.             }
  23497.         }
  23498.         return $ret;
  23499.     }
  23500.  
  23501.     // }}}
  23502.     // {{{ getOptions()
  23503.  
  23504.     function getOptions($command)
  23505.     {
  23506.         $shortcuts = $this->getShortcuts();
  23507.         if (isset($shortcuts[$command])) {
  23508.             $command = $shortcuts[$command];
  23509.         }
  23510.         return @$this->commands[$command]['options'];
  23511.     }
  23512.  
  23513.     // }}}
  23514.     // {{{ getGetoptArgs()
  23515.  
  23516.     function getGetoptArgs($command, &$short_args, &$long_args)
  23517.     {
  23518.         $short_args = "";
  23519.         $long_args = array();
  23520.         if (empty($this->commands[$command]) || empty($this->commands[$command]['options'])) {
  23521.             return;
  23522.         }
  23523.         reset($this->commands[$command]['options']);
  23524.         while (list($option, $info) = each($this->commands[$command]['options'])) {
  23525.             $larg = $sarg = '';
  23526.             if (isset($info['arg'])) {
  23527.                 if ($info['arg']{0} == '(') {
  23528.                     $larg = '==';
  23529.                     $sarg = '::';
  23530.                     $arg = substr($info['arg'], 1, -1);
  23531.                 } else {
  23532.                     $larg = '=';
  23533.                     $sarg = ':';
  23534.                     $arg = $info['arg'];
  23535.                 }
  23536.             }
  23537.             if (isset($info['shortopt'])) {
  23538.                 $short_args .= $info['shortopt'] . $sarg;
  23539.             }
  23540.             $long_args[] = $option . $larg;
  23541.         }
  23542.     }
  23543.  
  23544.     // }}}
  23545.     // {{{ getHelp()
  23546.     /**
  23547.     * Returns the help message for the given command
  23548.     *
  23549.     * @param string $command The command
  23550.     * @return mixed A fail string if the command does not have help or
  23551.     *               a two elements array containing [0]=>help string,
  23552.     *               [1]=> help string for the accepted cmd args
  23553.     */
  23554.     function getHelp($command)
  23555.     {
  23556.         $config = &PEAR_Config::singleton();
  23557.         $help = @$this->commands[$command]['doc'];
  23558.         if (empty($help)) {
  23559.             // XXX (cox) Fallback to summary if there is no doc (show both?)
  23560.             if (!$help = @$this->commands[$command]['summary']) {
  23561.                 return "No help for command \"$command\"";
  23562.             }
  23563.         }
  23564.         if (preg_match_all('/{config\s+([^\}]+)}/e', $help, $matches)) {
  23565.             foreach($matches[0] as $k => $v) {
  23566.                 $help = preg_replace("/$v/", $config->get($matches[1][$k]), $help);
  23567.             }
  23568.         }
  23569.         return array($help, $this->getHelpArgs($command));
  23570.     }
  23571.  
  23572.     // }}}
  23573.     // {{{ getHelpArgs()
  23574.     /**
  23575.     * Returns the help for the accepted arguments of a command
  23576.     *
  23577.     * @param  string $command
  23578.     * @return string The help string
  23579.     */
  23580.     function getHelpArgs($command)
  23581.     {
  23582.         if (isset($this->commands[$command]['options']) &&
  23583.             count($this->commands[$command]['options']))
  23584.         {
  23585.             $help = "Options:\n";
  23586.             foreach ($this->commands[$command]['options'] as $k => $v) {
  23587.                 if (isset($v['arg'])) {
  23588.                     if ($v['arg']{0} == '(') {
  23589.                         $arg = substr($v['arg'], 1, -1);
  23590.                         $sapp = " [$arg]";
  23591.                         $lapp = "[=$arg]";
  23592.                     } else {
  23593.                         $sapp = " $v[arg]";
  23594.                         $lapp = "=$v[arg]";
  23595.                     }
  23596.                 } else {
  23597.                     $sapp = $lapp = "";
  23598.                 }
  23599.                 if (isset($v['shortopt'])) {
  23600.                     $s = $v['shortopt'];
  23601.                     @$help .= "  -$s$sapp, --$k$lapp\n";
  23602.                 } else {
  23603.                     @$help .= "  --$k$lapp\n";
  23604.                 }
  23605.                 $p = "        ";
  23606.                 $doc = rtrim(str_replace("\n", "\n$p", $v['doc']));
  23607.                 $help .= "        $doc\n";
  23608.             }
  23609.             return $help;
  23610.         }
  23611.         return null;
  23612.     }
  23613.  
  23614.     // }}}
  23615.     // {{{ run()
  23616.  
  23617.     function run($command, $options, $params)
  23618.     {
  23619.         if (empty($this->commands[$command]['function'])) {
  23620.             // look for shortcuts
  23621.             foreach (array_keys($this->commands) as $cmd) {
  23622.                 if (isset($this->commands[$cmd]['shortcut']) && $this->commands[$cmd]['shortcut'] == $command) {
  23623.                     if (empty($this->commands[$cmd]['function'])) {
  23624.                         return $this->raiseError("unknown command `$command'");
  23625.                     } else {
  23626.                         $func = $this->commands[$cmd]['function'];
  23627.                     }
  23628.                     $command = $cmd;
  23629.                     break;
  23630.                 }
  23631.             }
  23632.         } else {
  23633.             $func = $this->commands[$command]['function'];
  23634.         }
  23635.         return $this->$func($command, $options, $params);
  23636.     }
  23637.  
  23638.     // }}}
  23639. }
  23640.  
  23641. ?>
  23642. PEAR-1.4.11/PEAR/Command/Config.xml100644   1750   1750        6466 10470570063  11621 <commands version="1.0">
  23643.  <config-show>
  23644.   <summary>Show All Settings</summary>
  23645.   <function>doConfigShow</function>
  23646.   <shortcut>csh</shortcut>
  23647.   <options>
  23648.    <channel>
  23649.     <shortopt>c</shortopt>
  23650.     <doc>show configuration variables for another channel</doc>
  23651.     <arg>CHAN</arg>
  23652.    </channel>
  23653.   </options>
  23654.   <doc>[layer]
  23655. Displays all configuration values.  An optional argument
  23656. may be used to tell which configuration layer to display.  Valid
  23657. configuration layers are "user", "system" and "default". To display
  23658. configurations for different channels, set the default_channel
  23659. configuration variable and run config-show again.
  23660. </doc>
  23661.  </config-show>
  23662.  <config-get>
  23663.   <summary>Show One Setting</summary>
  23664.   <function>doConfigGet</function>
  23665.   <shortcut>cg</shortcut>
  23666.   <options>
  23667.    <channel>
  23668.     <shortopt>c</shortopt>
  23669.     <doc>show configuration variables for another channel</doc>
  23670.     <arg>CHAN</arg>
  23671.    </channel>
  23672.   </options>
  23673.   <doc><parameter> [layer]
  23674. Displays the value of one configuration parameter.  The
  23675. first argument is the name of the parameter, an optional second argument
  23676. may be used to tell which configuration layer to look in.  Valid configuration
  23677. layers are "user", "system" and "default".  If no layer is specified, a value
  23678. will be picked from the first layer that defines the parameter, in the order
  23679. just specified.  The configuration value will be retrieved for the channel
  23680. specified by the default_channel configuration variable.
  23681. </doc>
  23682.  </config-get>
  23683.  <config-set>
  23684.   <summary>Change Setting</summary>
  23685.   <function>doConfigSet</function>
  23686.   <shortcut>cs</shortcut>
  23687.   <options>
  23688.    <channel>
  23689.     <shortopt>c</shortopt>
  23690.     <doc>show configuration variables for another channel</doc>
  23691.     <arg>CHAN</arg>
  23692.    </channel>
  23693.   </options>
  23694.   <doc><parameter> <value> [layer]
  23695. Sets the value of one configuration parameter.  The first argument is
  23696. the name of the parameter, the second argument is the new value.  Some
  23697. parameters are subject to validation, and the command will fail with
  23698. an error message if the new value does not make sense.  An optional
  23699. third argument may be used to specify in which layer to set the
  23700. configuration parameter.  The default layer is "user".  The
  23701. configuration value will be set for the current channel, which
  23702. is controlled by the default_channel configuration variable.
  23703. </doc>
  23704.  </config-set>
  23705.  <config-help>
  23706.   <summary>Show Information About Setting</summary>
  23707.   <function>doConfigHelp</function>
  23708.   <shortcut>ch</shortcut>
  23709.   <options />
  23710.   <doc>[parameter]
  23711. Displays help for a configuration parameter.  Without arguments it
  23712. displays help for all configuration parameters.
  23713. </doc>
  23714.  </config-help>
  23715.  <config-create>
  23716.   <summary>Create a Default configuration file</summary>
  23717.   <function>doConfigCreate</function>
  23718.   <shortcut>coc</shortcut>
  23719.   <options>
  23720.    <windows>
  23721.     <shortopt>w</shortopt>
  23722.     <doc>create a config file for a windows install</doc>
  23723.    </windows>
  23724.   </options>
  23725.   <doc><root path> <filename>
  23726. Create a default configuration file with all directory configuration
  23727. variables set to subdirectories of <root path>, and save it as <filename>.
  23728. This is useful especially for creating a configuration file for a remote
  23729. PEAR installation (using the --remoteconfig option of install, upgrade,
  23730. and uninstall).
  23731. </doc>
  23732.  </config-create>
  23733. </commands>PEAR-1.4.11/PEAR/Command/Config.php100644   1750   1750       35516 10470570063  11626 <?php
  23734. /**
  23735.  * PEAR_Command_Config (config-show, config-get, config-set, config-help, config-create commands)
  23736.  *
  23737.  * PHP versions 4 and 5
  23738.  *
  23739.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  23740.  * that is available through the world-wide-web at the following URI:
  23741.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  23742.  * the PHP License and are unable to obtain it through the web, please
  23743.  * send a note to license@php.net so we can mail you a copy immediately.
  23744.  *
  23745.  * @category   pear
  23746.  * @package    PEAR
  23747.  * @author     Stig Bakken <ssb@php.net>
  23748.  * @author     Greg Beaver <cellog@php.net>
  23749.  * @copyright  1997-2006 The PHP Group
  23750.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23751.  * @version    CVS: $Id: Config.php,v 1.51.2.1 2006/06/04 12:11:39 pajoye Exp $
  23752.  * @link       http://pear.php.net/package/PEAR
  23753.  * @since      File available since Release 0.1
  23754.  */
  23755.  
  23756. /**
  23757.  * base class
  23758.  */
  23759. require_once 'PEAR/Command/Common.php';
  23760.  
  23761. /**
  23762.  * PEAR commands for managing configuration data.
  23763.  *
  23764.  * @category   pear
  23765.  * @package    PEAR
  23766.  * @author     Stig Bakken <ssb@php.net>
  23767.  * @author     Greg Beaver <cellog@php.net>
  23768.  * @copyright  1997-2006 The PHP Group
  23769.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  23770.  * @version    Release: 1.4.11
  23771.  * @link       http://pear.php.net/package/PEAR
  23772.  * @since      Class available since Release 0.1
  23773.  */
  23774. class PEAR_Command_Config extends PEAR_Command_Common
  23775. {
  23776.     // {{{ properties
  23777.  
  23778.     var $commands = array(
  23779.         'config-show' => array(
  23780.             'summary' => 'Show All Settings',
  23781.             'function' => 'doConfigShow',
  23782.             'shortcut' => 'csh',
  23783.             'options' => array(
  23784.                 'channel' => array(
  23785.                     'shortopt' => 'c',
  23786.                     'doc' => 'show configuration variables for another channel',
  23787.                     'arg' => 'CHAN',
  23788.                     ),
  23789. ),
  23790.             'doc' => '[layer]
  23791. Displays all configuration values.  An optional argument
  23792. may be used to tell which configuration layer to display.  Valid
  23793. configuration layers are "user", "system" and "default". To display
  23794. configurations for different channels, set the default_channel
  23795. configuration variable and run config-show again.
  23796. ',
  23797.             ),
  23798.         'config-get' => array(
  23799.             'summary' => 'Show One Setting',
  23800.             'function' => 'doConfigGet',
  23801.             'shortcut' => 'cg',
  23802.             'options' => array(
  23803.                 'channel' => array(
  23804.                     'shortopt' => 'c',
  23805.                     'doc' => 'show configuration variables for another channel',
  23806.                     'arg' => 'CHAN',
  23807.                     ),
  23808. ),
  23809.             'doc' => '<parameter> [layer]
  23810. Displays the value of one configuration parameter.  The
  23811. first argument is the name of the parameter, an optional second argument
  23812. may be used to tell which configuration layer to look in.  Valid configuration
  23813. layers are "user", "system" and "default".  If no layer is specified, a value
  23814. will be picked from the first layer that defines the parameter, in the order
  23815. just specified.  The configuration value will be retrieved for the channel
  23816. specified by the default_channel configuration variable.
  23817. ',
  23818.             ),
  23819.         'config-set' => array(
  23820.             'summary' => 'Change Setting',
  23821.             'function' => 'doConfigSet',
  23822.             'shortcut' => 'cs',
  23823.             'options' => array(
  23824.                 'channel' => array(
  23825.                     'shortopt' => 'c',
  23826.                     'doc' => 'show configuration variables for another channel',
  23827.                     'arg' => 'CHAN',
  23828.                     ),
  23829. ),
  23830.             'doc' => '<parameter> <value> [layer]
  23831. Sets the value of one configuration parameter.  The first argument is
  23832. the name of the parameter, the second argument is the new value.  Some
  23833. parameters are subject to validation, and the command will fail with
  23834. an error message if the new value does not make sense.  An optional
  23835. third argument may be used to specify in which layer to set the
  23836. configuration parameter.  The default layer is "user".  The
  23837. configuration value will be set for the current channel, which
  23838. is controlled by the default_channel configuration variable.
  23839. ',
  23840.             ),
  23841.         'config-help' => array(
  23842.             'summary' => 'Show Information About Setting',
  23843.             'function' => 'doConfigHelp',
  23844.             'shortcut' => 'ch',
  23845.             'options' => array(),
  23846.             'doc' => '[parameter]
  23847. Displays help for a configuration parameter.  Without arguments it
  23848. displays help for all configuration parameters.
  23849. ',
  23850.            ),
  23851.         'config-create' => array(
  23852.             'summary' => 'Create a Default configuration file',
  23853.             'function' => 'doConfigCreate',
  23854.             'shortcut' => 'coc',
  23855.             'options' => array(
  23856.                 'windows' => array(
  23857.                     'shortopt' => 'w',
  23858.                     'doc' => 'create a config file for a windows install',
  23859.                     ),
  23860.             ),
  23861.             'doc' => '<root path> <filename>
  23862. Create a default configuration file with all directory configuration
  23863. variables set to subdirectories of <root path>, and save it as <filename>.
  23864. This is useful especially for creating a configuration file for a remote
  23865. PEAR installation (using the --remoteconfig option of install, upgrade,
  23866. and uninstall).
  23867. ',
  23868.             ),
  23869.         );
  23870.  
  23871.     // }}}
  23872.     // {{{ constructor
  23873.  
  23874.     /**
  23875.      * PEAR_Command_Config constructor.
  23876.      *
  23877.      * @access public
  23878.      */
  23879.     function PEAR_Command_Config(&$ui, &$config)
  23880.     {
  23881.         parent::PEAR_Command_Common($ui, $config);
  23882.     }
  23883.  
  23884.     // }}}
  23885.  
  23886.     // {{{ doConfigShow()
  23887.  
  23888.     function doConfigShow($command, $options, $params)
  23889.     {
  23890.         if (is_array($params)) {
  23891.             $layer = isset($params[0]) ? $params[0] : NULL;
  23892.         } else {
  23893.             $layer = NULL;
  23894.         }
  23895.  
  23896.         // $params[0] -> the layer
  23897.         if ($error = $this->_checkLayer($layer)) {
  23898.             return $this->raiseError("config-show:$error");
  23899.         }
  23900.         $keys = $this->config->getKeys();
  23901.         sort($keys);
  23902.         $channel = isset($options['channel']) ? $options['channel'] :
  23903.             $this->config->get('default_channel');
  23904.         $reg = &$this->config->getRegistry();
  23905.         if (!$reg->channelExists($channel)) {
  23906.             return $this->raiseError('Channel "' . $channel . '" does not exist');
  23907.         }
  23908.         $data = array('caption' => 'Configuration (channel ' . $channel . '):');
  23909.         foreach ($keys as $key) {
  23910.             $type = $this->config->getType($key);
  23911.             $value = $this->config->get($key, $layer, $channel);
  23912.             if ($type == 'password' && $value) {
  23913.                 $value = '********';
  23914.             }
  23915.             if ($value === false) {
  23916.                 $value = 'false';
  23917.             } elseif ($value === true) {
  23918.                 $value = 'true';
  23919.             }
  23920.             $data['data'][$this->config->getGroup($key)][] = array($this->config->getPrompt($key) , $key, $value);
  23921.         }
  23922.         foreach ($this->config->getLayers() as $layer) {
  23923.             $data['data']['Config Files'][] = array(ucfirst($layer) . ' Configuration File', 'Filename' , $this->config->getConfFile($layer));
  23924.         }
  23925.  
  23926.         $this->ui->outputData($data, $command);
  23927.         return true;
  23928.     }
  23929.  
  23930.     // }}}
  23931.     // {{{ doConfigGet()
  23932.  
  23933.     function doConfigGet($command, $options, $params)
  23934.     {
  23935.         if (!is_array($params)) {
  23936.             $args_cnt = 0;
  23937.         } else {
  23938.             $args_cnt  = count($params);
  23939.         }
  23940.  
  23941.         switch ($args_cnt) {
  23942.             case 1:
  23943.                 $config_key = $params[0];
  23944.                 $layer = NULL;
  23945.                 break;
  23946.             case 2:
  23947.                 $config_key = $params[0];
  23948.                 $layer = $params[1];
  23949.                 if ($error = $this->_checkLayer($layer)) {
  23950.                     return $this->raiseError("config-get:$error");
  23951.                 }
  23952.                 break;
  23953.             case 0:
  23954.             default:
  23955.                 return $this->raiseError("config-get expects 1 or 2 parameters");
  23956.         }
  23957.  
  23958.         $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
  23959.         $reg = &$this->config->getRegistry();
  23960.  
  23961.         if (!$reg->channelExists($channel)) {
  23962.             return $this->raiseError('Channel "' . $channel . '" does not exist');
  23963.         }
  23964.  
  23965.         $this->ui->outputData($this->config->get($config_key, $layer, $channel), $command);
  23966.  
  23967.         return true;
  23968.     }
  23969.  
  23970.     // }}}
  23971.     // {{{ doConfigSet()
  23972.  
  23973.     function doConfigSet($command, $options, $params)
  23974.     {
  23975.         // $param[0] -> a parameter to set
  23976.         // $param[1] -> the value for the parameter
  23977.         // $param[2] -> the layer
  23978.         $failmsg = '';
  23979.         if (sizeof($params) < 2 || sizeof($params) > 3) {
  23980.             $failmsg .= "config-set expects 2 or 3 parameters";
  23981.             return PEAR::raiseError($failmsg);
  23982.         }
  23983.         if (isset($params[2]) && $error = $this->_checkLayer($params[2])) {
  23984.             $failmsg .= $error;
  23985.             return PEAR::raiseError("config-set:$failmsg");
  23986.         }
  23987.         $channel = isset($options['channel']) ? $options['channel'] :
  23988.             $this->config->get('default_channel');
  23989.         $reg = &$this->config->getRegistry();
  23990.         if (!$reg->channelExists($channel)) {
  23991.             return $this->raiseError('Channel "' . $channel . '" does not exist');
  23992.         }
  23993.         if ($params[0] == 'default_channel') {
  23994.             if (!$reg->channelExists($params[1])) {
  23995.                 return $this->raiseError('Channel "' . $params[1] . '" does not exist');
  23996.             }
  23997.         }
  23998.         if (count($params) == 2) {
  23999.             array_push($params, 'user');
  24000.             $layer = 'user';
  24001.         } else {
  24002.             $layer = $params[2];
  24003.         }
  24004.         array_push($params, $channel);
  24005.         if (!call_user_func_array(array(&$this->config, 'set'), $params))
  24006.         {
  24007.             array_pop($params);
  24008.             $failmsg = "config-set (" . implode(", ", $params) . ") failed, channel $channel";
  24009.         } else {
  24010.             $this->config->store($layer);
  24011.         }
  24012.         if ($failmsg) {
  24013.             return $this->raiseError($failmsg);
  24014.         }
  24015.         $this->ui->outputData('config-set succeeded', $command);
  24016.         return true;
  24017.     }
  24018.  
  24019.     // }}}
  24020.     // {{{ doConfigHelp()
  24021.  
  24022.     function doConfigHelp($command, $options, $params)
  24023.     {
  24024.         if (empty($params)) {
  24025.             $params = $this->config->getKeys();
  24026.         }
  24027.         $data['caption']  = "Config help" . ((count($params) == 1) ? " for $params[0]" : '');
  24028.         $data['headline'] = array('Name', 'Type', 'Description');
  24029.         $data['border']   = true;
  24030.         foreach ($params as $name) {
  24031.             $type = $this->config->getType($name);
  24032.             $docs = $this->config->getDocs($name);
  24033.             if ($type == 'set') {
  24034.                 $docs = rtrim($docs) . "\nValid set: " .
  24035.                     implode(' ', $this->config->getSetValues($name));
  24036.             }
  24037.             $data['data'][] = array($name, $type, $docs);
  24038.         }
  24039.         $this->ui->outputData($data, $command);
  24040.     }
  24041.  
  24042.     // }}}
  24043.     // {{{ doConfigCreate()
  24044.  
  24045.     function doConfigCreate($command, $options, $params)
  24046.     {
  24047.         if (count($params) != 2) {
  24048.             return PEAR::raiseError('config-create: must have 2 parameters, root path and ' .
  24049.                 'filename to save as');
  24050.         }
  24051.         $root = $params[0];
  24052.         // Clean up the DIRECTORY_SEPARATOR mess
  24053.         $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  24054.         $root = preg_replace(array('!\\\\+!', '!/+!', "!$ds2+!"),
  24055.                              array('/', '/', '/'),
  24056.                             $root);
  24057.         if ($root{0} != '/') {
  24058.             if (isset($options['windows'])) {
  24059.                 if (!preg_match('/^[A-Za-z]:/', $root)) {
  24060.                     return PEAR::raiseError('Root directory must be an absolute path beginning ' .
  24061.                         'with "\\" or "C:\\", was: "' . $root . '"');
  24062.                 }
  24063.             } else {
  24064.                 return PEAR::raiseError('Root directory must be an absolute path beginning ' .
  24065.                     'with "/", was: "' . $root . '"');
  24066.             }
  24067.         }
  24068.         $windows = isset($options['windows']);
  24069.         if ($windows) {
  24070.             $root = str_replace('/', '\\', $root);
  24071.         }
  24072.         if (!file_exists($params[1])) {
  24073.             if (!@touch($params[1])) {
  24074.                 return PEAR::raiseError('Could not create "' . $params[1] . '"');
  24075.             }
  24076.         }
  24077.         $params[1] = realpath($params[1]);
  24078.         $config = &new PEAR_Config($params[1], '#no#system#config#', false, false);
  24079.         if ($root{strlen($root) - 1} == '/') {
  24080.             $root = substr($root, 0, strlen($root) - 1);
  24081.         }
  24082.         $config->noRegistry();
  24083.         $config->set('php_dir', $windows ? "$root\\pear\\php" : "$root/pear/php", 'user');
  24084.         $config->set('data_dir', $windows ? "$root\\pear\\data" : "$root/pear/data");
  24085.         $config->set('ext_dir', $windows ? "$root\\pear\\ext" : "$root/pear/ext");
  24086.         $config->set('doc_dir', $windows ? "$root\\pear\\docs" : "$root/pear/docs");
  24087.         $config->set('test_dir', $windows ? "$root\\pear\\tests" : "$root/pear/tests");
  24088.         $config->set('cache_dir', $windows ? "$root\\pear\\cache" : "$root/pear/cache");
  24089.         $config->set('bin_dir', $windows ? "$root\\pear" : "$root/pear");
  24090.         $config->writeConfigFile();
  24091.         $this->_showConfig($config);
  24092.         $this->ui->outputData('Successfully created default configuration file "' . $params[1] . '"',
  24093.             $command);
  24094.     }
  24095.  
  24096.     // }}}
  24097.  
  24098.     function _showConfig(&$config)
  24099.     {
  24100.         $params = array('user');
  24101.         $keys = $config->getKeys();
  24102.         sort($keys);
  24103.         $channel = 'pear.php.net';
  24104.         $data = array('caption' => 'Configuration (channel ' . $channel . '):');
  24105.         foreach ($keys as $key) {
  24106.             $type = $config->getType($key);
  24107.             $value = $config->get($key, 'user', $channel);
  24108.             if ($type == 'password' && $value) {
  24109.                 $value = '********';
  24110.             }
  24111.             if ($value === false) {
  24112.                 $value = 'false';
  24113.             } elseif ($value === true) {
  24114.                 $value = 'true';
  24115.             }
  24116.             $data['data'][$config->getGroup($key)][] =
  24117.                 array($config->getPrompt($key) , $key, $value);
  24118.         }
  24119.         foreach ($config->getLayers() as $layer) {
  24120.             $data['data']['Config Files'][] =
  24121.                 array(ucfirst($layer) . ' Configuration File', 'Filename' ,
  24122.                     $config->getConfFile($layer));
  24123.         }
  24124.  
  24125.         $this->ui->outputData($data, 'config-show');
  24126.         return true;
  24127.     }
  24128.     // {{{ _checkLayer()
  24129.  
  24130.     /**
  24131.      * Checks if a layer is defined or not
  24132.      *
  24133.      * @param string $layer The layer to search for
  24134.      * @return mixed False on no error or the error message
  24135.      */
  24136.     function _checkLayer($layer = null)
  24137.     {
  24138.         if (!empty($layer) && $layer != 'default') {
  24139.             $layers = $this->config->getLayers();
  24140.             if (!in_array($layer, $layers)) {
  24141.                 return " only the layers: \"" . implode('" or "', $layers) . "\" are supported";
  24142.             }
  24143.         }
  24144.         return false;
  24145.     }
  24146.  
  24147.     // }}}
  24148. }
  24149.  
  24150. ?>
  24151. PEAR-1.4.11/PEAR/Command/Install.xml100644   1750   1750       17207 10470570063  12035 <commands version="1.0">
  24152.  <install>
  24153.   <summary>Install Package</summary>
  24154.   <function>doInstall</function>
  24155.   <shortcut>i</shortcut>
  24156.   <options>
  24157.    <force>
  24158.     <shortopt>f</shortopt>
  24159.     <doc>will overwrite newer installed packages</doc>
  24160.    </force>
  24161.    <loose>
  24162.     <shortopt>l</shortopt>
  24163.     <doc>do not check for recommended dependency version</doc>
  24164.    </loose>
  24165.    <nodeps>
  24166.     <shortopt>n</shortopt>
  24167.     <doc>ignore dependencies, install anyway</doc>
  24168.    </nodeps>
  24169.    <register-only>
  24170.     <shortopt>r</shortopt>
  24171.     <doc>do not install files, only register the package as installed</doc>
  24172.    </register-only>
  24173.    <soft>
  24174.     <shortopt>s</shortopt>
  24175.     <doc>soft install, fail silently, or upgrade if already installed</doc>
  24176.    </soft>
  24177.    <nobuild>
  24178.     <shortopt>B</shortopt>
  24179.     <doc>don't build C extensions</doc>
  24180.    </nobuild>
  24181.    <nocompress>
  24182.     <shortopt>Z</shortopt>
  24183.     <doc>request uncompressed files when downloading</doc>
  24184.    </nocompress>
  24185.    <installroot>
  24186.     <shortopt>R</shortopt>
  24187.     <arg>DIR</arg>
  24188.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  24189.    </installroot>
  24190.    <ignore-errors>
  24191.     <doc>force install even if there were errors</doc>
  24192.    </ignore-errors>
  24193.    <alldeps>
  24194.     <shortopt>a</shortopt>
  24195.     <doc>install all required and optional dependencies</doc>
  24196.    </alldeps>
  24197.    <onlyreqdeps>
  24198.     <shortopt>o</shortopt>
  24199.     <doc>install all required dependencies</doc>
  24200.    </onlyreqdeps>
  24201.    <offline>
  24202.     <shortopt>O</shortopt>
  24203.     <doc>do not attempt to download any urls or contact channels</doc>
  24204.    </offline>
  24205.    <pretend>
  24206.     <shortopt>p</shortopt>
  24207.     <doc>Only list the packages that would be downloaded</doc>
  24208.    </pretend>
  24209.   </options>
  24210.   <doc>[channel/]<package> ...
  24211. Installs one or more PEAR packages.  You can specify a package to
  24212. install in four ways:
  24213.  
  24214. "Package-1.0.tgz" : installs from a local file
  24215.  
  24216. "http://example.com/Package-1.0.tgz" : installs from
  24217. anywhere on the net.
  24218.  
  24219. "package.xml" : installs the package described in
  24220. package.xml.  Useful for testing, or for wrapping a PEAR package in
  24221. another package manager such as RPM.
  24222.  
  24223. "Package[-version/state][.tar]" : queries your default channel's server
  24224. ({config master_server}) and downloads the newest package with
  24225. the preferred quality/state ({config preferred_state}).
  24226.  
  24227. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  24228. Package state beta, use "Package-beta."  To retrieve an uncompressed
  24229. file, append .tar (make sure there is no file by the same name first)
  24230.  
  24231. To download a package from another channel, prefix with the channel name like
  24232. "channel/Package"
  24233.  
  24234. More than one package may be specified at once.  It is ok to mix these
  24235. four ways of specifying packages.
  24236. </doc>
  24237.  </install>
  24238.  <upgrade>
  24239.   <summary>Upgrade Package</summary>
  24240.   <function>doInstall</function>
  24241.   <shortcut>up</shortcut>
  24242.   <options>
  24243.    <force>
  24244.     <shortopt>f</shortopt>
  24245.     <doc>overwrite newer installed packages</doc>
  24246.    </force>
  24247.    <loose>
  24248.     <shortopt>l</shortopt>
  24249.     <doc>do not check for recommended dependency version</doc>
  24250.    </loose>
  24251.    <nodeps>
  24252.     <shortopt>n</shortopt>
  24253.     <doc>ignore dependencies, upgrade anyway</doc>
  24254.    </nodeps>
  24255.    <register-only>
  24256.     <shortopt>r</shortopt>
  24257.     <doc>do not install files, only register the package as upgraded</doc>
  24258.    </register-only>
  24259.    <nobuild>
  24260.     <shortopt>B</shortopt>
  24261.     <doc>don't build C extensions</doc>
  24262.    </nobuild>
  24263.    <nocompress>
  24264.     <shortopt>Z</shortopt>
  24265.     <doc>request uncompressed files when downloading</doc>
  24266.    </nocompress>
  24267.    <installroot>
  24268.     <shortopt>R</shortopt>
  24269.     <arg>DIR</arg>
  24270.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  24271.    </installroot>
  24272.    <ignore-errors>
  24273.     <doc>force install even if there were errors</doc>
  24274.    </ignore-errors>
  24275.    <alldeps>
  24276.     <shortopt>a</shortopt>
  24277.     <doc>install all required and optional dependencies</doc>
  24278.    </alldeps>
  24279.    <onlyreqdeps>
  24280.     <shortopt>o</shortopt>
  24281.     <doc>install all required dependencies</doc>
  24282.    </onlyreqdeps>
  24283.    <offline>
  24284.     <shortopt>O</shortopt>
  24285.     <doc>do not attempt to download any urls or contact channels</doc>
  24286.    </offline>
  24287.    <pretend>
  24288.     <shortopt>p</shortopt>
  24289.     <doc>Only list the packages that would be downloaded</doc>
  24290.    </pretend>
  24291.   </options>
  24292.   <doc><package> ...
  24293. Upgrades one or more PEAR packages.  See documentation for the
  24294. "install" command for ways to specify a package.
  24295.  
  24296. When upgrading, your package will be updated if the provided new
  24297. package has a higher version number (use the -f option if you need to
  24298. upgrade anyway).
  24299.  
  24300. More than one package may be specified at once.
  24301. </doc>
  24302.  </upgrade>
  24303.  <upgrade-all>
  24304.   <summary>Upgrade All Packages</summary>
  24305.   <function>doInstall</function>
  24306.   <shortcut>ua</shortcut>
  24307.   <options>
  24308.    <nodeps>
  24309.     <shortopt>n</shortopt>
  24310.     <doc>ignore dependencies, upgrade anyway</doc>
  24311.    </nodeps>
  24312.    <register-only>
  24313.     <shortopt>r</shortopt>
  24314.     <doc>do not install files, only register the package as upgraded</doc>
  24315.    </register-only>
  24316.    <nobuild>
  24317.     <shortopt>B</shortopt>
  24318.     <doc>don't build C extensions</doc>
  24319.    </nobuild>
  24320.    <nocompress>
  24321.     <shortopt>Z</shortopt>
  24322.     <doc>request uncompressed files when downloading</doc>
  24323.    </nocompress>
  24324.    <installroot>
  24325.     <shortopt>R</shortopt>
  24326.     <arg>DIR</arg>
  24327.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  24328.    </installroot>
  24329.    <ignore-errors>
  24330.     <doc>force install even if there were errors</doc>
  24331.    </ignore-errors>
  24332.    <loose>
  24333.     <doc>do not check for recommended dependency version</doc>
  24334.    </loose>
  24335.   </options>
  24336.   <doc>
  24337. Upgrades all packages that have a newer release available.  Upgrades are
  24338. done only if there is a release available of the state specified in
  24339. "preferred_state" (currently {config preferred_state}), or a state considered
  24340. more stable.
  24341. </doc>
  24342.  </upgrade-all>
  24343.  <uninstall>
  24344.   <summary>Un-install Package</summary>
  24345.   <function>doUninstall</function>
  24346.   <shortcut>un</shortcut>
  24347.   <options>
  24348.    <nodeps>
  24349.     <shortopt>n</shortopt>
  24350.     <doc>ignore dependencies, uninstall anyway</doc>
  24351.    </nodeps>
  24352.    <register-only>
  24353.     <shortopt>r</shortopt>
  24354.     <doc>do not remove files, only register the packages as not installed</doc>
  24355.    </register-only>
  24356.    <installroot>
  24357.     <shortopt>R</shortopt>
  24358.     <arg>DIR</arg>
  24359.     <doc>root directory used when installing files (ala PHP's INSTALL_ROOT)</doc>
  24360.    </installroot>
  24361.    <ignore-errors>
  24362.     <doc>force install even if there were errors</doc>
  24363.    </ignore-errors>
  24364.    <offline>
  24365.     <shortopt>O</shortopt>
  24366.     <doc>do not attempt to uninstall remotely</doc>
  24367.    </offline>
  24368.   </options>
  24369.   <doc>[channel/]<package> ...
  24370. Uninstalls one or more PEAR packages.  More than one package may be
  24371. specified at once.  Prefix with channel name to uninstall from a
  24372. channel not in your default channel ({config default_channel})
  24373. </doc>
  24374.  </uninstall>
  24375.  <bundle>
  24376.   <summary>Unpacks a Pecl Package</summary>
  24377.   <function>doBundle</function>
  24378.   <shortcut>bun</shortcut>
  24379.   <options>
  24380.    <destination>
  24381.     <shortopt>d</shortopt>
  24382.     <arg>DIR</arg>
  24383.     <doc>Optional destination directory for unpacking (defaults to current path or "ext" if exists)</doc>
  24384.    </destination>
  24385.    <force>
  24386.     <shortopt>f</shortopt>
  24387.     <doc>Force the unpacking even if there were errors in the package</doc>
  24388.    </force>
  24389.   </options>
  24390.   <doc><package>
  24391. Unpacks a Pecl Package into the selected location. It will download the
  24392. package if needed.
  24393. </doc>
  24394.  </bundle>
  24395.  <run-scripts>
  24396.   <summary>Run Post-Install Scripts bundled with a package</summary>
  24397.   <function>doRunScripts</function>
  24398.   <shortcut>rs</shortcut>
  24399.   <options />
  24400.   <doc><package>
  24401. Run post-installation scripts in package <package>, if any exist.
  24402. </doc>
  24403.  </run-scripts>
  24404. </commands>PEAR-1.4.11/PEAR/Command/Install.php100644   1750   1750       77541 10470570063  12033 <?php
  24405. /**
  24406.  * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
  24407.  *
  24408.  * PHP versions 4 and 5
  24409.  *
  24410.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  24411.  * that is available through the world-wide-web at the following URI:
  24412.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  24413.  * the PHP License and are unable to obtain it through the web, please
  24414.  * send a note to license@php.net so we can mail you a copy immediately.
  24415.  *
  24416.  * @category   pear
  24417.  * @package    PEAR
  24418.  * @author     Stig Bakken <ssb@php.net>
  24419.  * @author     Greg Beaver <cellog@php.net>
  24420.  * @copyright  1997-2006 The PHP Group
  24421.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  24422.  * @version    CVS: $Id: Install.php,v 1.115 2006/03/02 18:14:13 cellog Exp $
  24423.  * @link       http://pear.php.net/package/PEAR
  24424.  * @since      File available since Release 0.1
  24425.  */
  24426.  
  24427. /**
  24428.  * base class
  24429.  */
  24430. require_once 'PEAR/Command/Common.php';
  24431.  
  24432. /**
  24433.  * PEAR commands for installation or deinstallation/upgrading of
  24434.  * packages.
  24435.  *
  24436.  * @category   pear
  24437.  * @package    PEAR
  24438.  * @author     Stig Bakken <ssb@php.net>
  24439.  * @author     Greg Beaver <cellog@php.net>
  24440.  * @copyright  1997-2006 The PHP Group
  24441.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  24442.  * @version    Release: 1.4.11
  24443.  * @link       http://pear.php.net/package/PEAR
  24444.  * @since      Class available since Release 0.1
  24445.  */
  24446. class PEAR_Command_Install extends PEAR_Command_Common
  24447. {
  24448.     // {{{ properties
  24449.  
  24450.     var $commands = array(
  24451.         'install' => array(
  24452.             'summary' => 'Install Package',
  24453.             'function' => 'doInstall',
  24454.             'shortcut' => 'i',
  24455.             'options' => array(
  24456.                 'force' => array(
  24457.                     'shortopt' => 'f',
  24458.                     'doc' => 'will overwrite newer installed packages',
  24459.                     ),
  24460.                 'loose' => array(
  24461.                     'shortopt' => 'l',
  24462.                     'doc' => 'do not check for recommended dependency version',
  24463.                     ),
  24464.                 'nodeps' => array(
  24465.                     'shortopt' => 'n',
  24466.                     'doc' => 'ignore dependencies, install anyway',
  24467.                     ),
  24468.                 'register-only' => array(
  24469.                     'shortopt' => 'r',
  24470.                     'doc' => 'do not install files, only register the package as installed',
  24471.                     ),
  24472.                 'soft' => array(
  24473.                     'shortopt' => 's',
  24474.                     'doc' => 'soft install, fail silently, or upgrade if already installed',
  24475.                     ),
  24476.                 'nobuild' => array(
  24477.                     'shortopt' => 'B',
  24478.                     'doc' => 'don\'t build C extensions',
  24479.                     ),
  24480.                 'nocompress' => array(
  24481.                     'shortopt' => 'Z',
  24482.                     'doc' => 'request uncompressed files when downloading',
  24483.                     ),
  24484.                 'installroot' => array(
  24485.                     'shortopt' => 'R',
  24486.                     'arg' => 'DIR',
  24487.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  24488.                     ),
  24489.                 'packagingroot' => array(
  24490.                     'shortopt' => 'P',
  24491.                     'arg' => 'DIR',
  24492.                     'doc' => 'root directory used when packaging files, like RPM packaging',
  24493.                     ),
  24494.                 'ignore-errors' => array(
  24495.                     'doc' => 'force install even if there were errors',
  24496.                     ),
  24497.                 'alldeps' => array(
  24498.                     'shortopt' => 'a',
  24499.                     'doc' => 'install all required and optional dependencies',
  24500.                     ),
  24501.                 'onlyreqdeps' => array(
  24502.                     'shortopt' => 'o',
  24503.                     'doc' => 'install all required dependencies',
  24504.                     ),
  24505.                 'offline' => array(
  24506.                     'shortopt' => 'O',
  24507.                     'doc' => 'do not attempt to download any urls or contact channels',
  24508.                     ),
  24509.                 'pretend' => array(
  24510.                     'shortopt' => 'p',
  24511.                     'doc' => 'Only list the packages that would be downloaded',
  24512.                     ),
  24513.                 ),
  24514.             'doc' => '[channel/]<package> ...
  24515. Installs one or more PEAR packages.  You can specify a package to
  24516. install in four ways:
  24517.  
  24518. "Package-1.0.tgz" : installs from a local file
  24519.  
  24520. "http://example.com/Package-1.0.tgz" : installs from
  24521. anywhere on the net.
  24522.  
  24523. "package.xml" : installs the package described in
  24524. package.xml.  Useful for testing, or for wrapping a PEAR package in
  24525. another package manager such as RPM.
  24526.  
  24527. "Package[-version/state][.tar]" : queries your default channel\'s server
  24528. ({config master_server}) and downloads the newest package with
  24529. the preferred quality/state ({config preferred_state}).
  24530.  
  24531. To retrieve Package version 1.1, use "Package-1.1," to retrieve
  24532. Package state beta, use "Package-beta."  To retrieve an uncompressed
  24533. file, append .tar (make sure there is no file by the same name first)
  24534.  
  24535. To download a package from another channel, prefix with the channel name like
  24536. "channel/Package"
  24537.  
  24538. More than one package may be specified at once.  It is ok to mix these
  24539. four ways of specifying packages.
  24540. '),
  24541.         'upgrade' => array(
  24542.             'summary' => 'Upgrade Package',
  24543.             'function' => 'doInstall',
  24544.             'shortcut' => 'up',
  24545.             'options' => array(
  24546.                 'force' => array(
  24547.                     'shortopt' => 'f',
  24548.                     'doc' => 'overwrite newer installed packages',
  24549.                     ),
  24550.                 'loose' => array(
  24551.                     'shortopt' => 'l',
  24552.                     'doc' => 'do not check for recommended dependency version',
  24553.                     ),
  24554.                 'nodeps' => array(
  24555.                     'shortopt' => 'n',
  24556.                     'doc' => 'ignore dependencies, upgrade anyway',
  24557.                     ),
  24558.                 'register-only' => array(
  24559.                     'shortopt' => 'r',
  24560.                     'doc' => 'do not install files, only register the package as upgraded',
  24561.                     ),
  24562.                 'nobuild' => array(
  24563.                     'shortopt' => 'B',
  24564.                     'doc' => 'don\'t build C extensions',
  24565.                     ),
  24566.                 'nocompress' => array(
  24567.                     'shortopt' => 'Z',
  24568.                     'doc' => 'request uncompressed files when downloading',
  24569.                     ),
  24570.                 'installroot' => array(
  24571.                     'shortopt' => 'R',
  24572.                     'arg' => 'DIR',
  24573.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  24574.                     ),
  24575.                 'packagingroot' => array(
  24576.                     'shortopt' => 'P',
  24577.                     'arg' => 'DIR',
  24578.                     'doc' => 'root directory used when packaging files, like RPM packaging',
  24579.                     ),
  24580.                 'ignore-errors' => array(
  24581.                     'doc' => 'force install even if there were errors',
  24582.                     ),
  24583.                 'alldeps' => array(
  24584.                     'shortopt' => 'a',
  24585.                     'doc' => 'install all required and optional dependencies',
  24586.                     ),
  24587.                 'onlyreqdeps' => array(
  24588.                     'shortopt' => 'o',
  24589.                     'doc' => 'install all required dependencies',
  24590.                     ),
  24591.                 'offline' => array(
  24592.                     'shortopt' => 'O',
  24593.                     'doc' => 'do not attempt to download any urls or contact channels',
  24594.                     ),
  24595.                 'pretend' => array(
  24596.                     'shortopt' => 'p',
  24597.                     'doc' => 'Only list the packages that would be downloaded',
  24598.                     ),
  24599.                 ),
  24600.             'doc' => '<package> ...
  24601. Upgrades one or more PEAR packages.  See documentation for the
  24602. "install" command for ways to specify a package.
  24603.  
  24604. When upgrading, your package will be updated if the provided new
  24605. package has a higher version number (use the -f option if you need to
  24606. upgrade anyway).
  24607.  
  24608. More than one package may be specified at once.
  24609. '),
  24610.         'upgrade-all' => array(
  24611.             'summary' => 'Upgrade All Packages',
  24612.             'function' => 'doInstall',
  24613.             'shortcut' => 'ua',
  24614.             'options' => array(
  24615.                 'nodeps' => array(
  24616.                     'shortopt' => 'n',
  24617.                     'doc' => 'ignore dependencies, upgrade anyway',
  24618.                     ),
  24619.                 'register-only' => array(
  24620.                     'shortopt' => 'r',
  24621.                     'doc' => 'do not install files, only register the package as upgraded',
  24622.                     ),
  24623.                 'nobuild' => array(
  24624.                     'shortopt' => 'B',
  24625.                     'doc' => 'don\'t build C extensions',
  24626.                     ),
  24627.                 'nocompress' => array(
  24628.                     'shortopt' => 'Z',
  24629.                     'doc' => 'request uncompressed files when downloading',
  24630.                     ),
  24631.                 'installroot' => array(
  24632.                     'shortopt' => 'R',
  24633.                     'arg' => 'DIR',
  24634.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
  24635.                     ),
  24636.                 'ignore-errors' => array(
  24637.                     'doc' => 'force install even if there were errors',
  24638.                     ),
  24639.                 'loose' => array(
  24640.                     'doc' => 'do not check for recommended dependency version',
  24641.                     ),
  24642.                 ),
  24643.             'doc' => '
  24644. Upgrades all packages that have a newer release available.  Upgrades are
  24645. done only if there is a release available of the state specified in
  24646. "preferred_state" (currently {config preferred_state}), or a state considered
  24647. more stable.
  24648. '),
  24649.         'uninstall' => array(
  24650.             'summary' => 'Un-install Package',
  24651.             'function' => 'doUninstall',
  24652.             'shortcut' => 'un',
  24653.             'options' => array(
  24654.                 'nodeps' => array(
  24655.                     'shortopt' => 'n',
  24656.                     'doc' => 'ignore dependencies, uninstall anyway',
  24657.                     ),
  24658.                 'register-only' => array(
  24659.                     'shortopt' => 'r',
  24660.                     'doc' => 'do not remove files, only register the packages as not installed',
  24661.                     ),
  24662.                 'installroot' => array(
  24663.                     'shortopt' => 'R',
  24664.                     'arg' => 'DIR',
  24665.                     'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
  24666.                     ),
  24667.                 'ignore-errors' => array(
  24668.                     'doc' => 'force install even if there were errors',
  24669.                     ),
  24670.                 'offline' => array(
  24671.                     'shortopt' => 'O',
  24672.                     'doc' => 'do not attempt to uninstall remotely',
  24673.                     ),
  24674.                 ),
  24675.             'doc' => '[channel/]<package> ...
  24676. Uninstalls one or more PEAR packages.  More than one package may be
  24677. specified at once.  Prefix with channel name to uninstall from a
  24678. channel not in your default channel ({config default_channel})
  24679. '),
  24680.         'bundle' => array(
  24681.             'summary' => 'Unpacks a Pecl Package',
  24682.             'function' => 'doBundle',
  24683.             'shortcut' => 'bun',
  24684.             'options' => array(
  24685.                 'destination' => array(
  24686.                    'shortopt' => 'd',
  24687.                     'arg' => 'DIR',
  24688.                     'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
  24689.                     ),
  24690.                 'force' => array(
  24691.                     'shortopt' => 'f',
  24692.                     'doc' => 'Force the unpacking even if there were errors in the package',
  24693.                 ),
  24694.             ),
  24695.             'doc' => '<package>
  24696. Unpacks a Pecl Package into the selected location. It will download the
  24697. package if needed.
  24698. '),
  24699.         'run-scripts' => array(
  24700.             'summary' => 'Run Post-Install Scripts bundled with a package',
  24701.             'function' => 'doRunScripts',
  24702.             'shortcut' => 'rs',
  24703.             'options' => array(
  24704.             ),
  24705.             'doc' => '<package>
  24706. Run post-installation scripts in package <package>, if any exist.
  24707. '),
  24708.     );
  24709.  
  24710.     // }}}
  24711.     // {{{ constructor
  24712.  
  24713.     /**
  24714.      * PEAR_Command_Install constructor.
  24715.      *
  24716.      * @access public
  24717.      */
  24718.     function PEAR_Command_Install(&$ui, &$config)
  24719.     {
  24720.         parent::PEAR_Command_Common($ui, $config);
  24721.     }
  24722.  
  24723.     // }}}
  24724.  
  24725.     /**
  24726.      * For unit testing purposes
  24727.      */
  24728.     function &getDownloader(&$ui, $options, &$config)
  24729.     {
  24730.         if (!class_exists('PEAR_Downloader')) {
  24731.             require_once 'PEAR/Downloader.php';
  24732.         }
  24733.         $a = &new PEAR_Downloader($ui, $options, $config);
  24734.         return $a;
  24735.     }
  24736.  
  24737.     /**
  24738.      * For unit testing purposes
  24739.      */
  24740.     function &getInstaller(&$ui)
  24741.     {
  24742.         if (!class_exists('PEAR_Installer')) {
  24743.             require_once 'PEAR/Installer.php';
  24744.         }
  24745.         $a = &new PEAR_Installer($ui);
  24746.         return $a;
  24747.     }
  24748.  
  24749.     // {{{ doInstall()
  24750.  
  24751.     function doInstall($command, $options, $params)
  24752.     {
  24753.         if (empty($this->installer)) {
  24754.             $this->installer = &$this->getInstaller($this->ui);
  24755.         }
  24756.         if ($command == 'upgrade') {
  24757.             $options['upgrade'] = true;
  24758.         }
  24759.         if (isset($options['installroot']) && isset($options['packagingroot'])) {
  24760.             return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
  24761.         }
  24762.         if (isset($options['packagingroot']) && $this->config->get('verbose') > 2) {
  24763.             $this->ui->outputData('using package root: ' . $options['packagingroot']);
  24764.         }
  24765.         $reg = &$this->config->getRegistry();
  24766.         if ($command == 'upgrade-all') {
  24767.             $options['upgrade'] = true;
  24768.             $reg = &$this->config->getRegistry();
  24769.             $savechannel = $this->config->get('default_channel');
  24770.             $params = array();
  24771.             foreach ($reg->listChannels() as $channel) {
  24772.                 if ($channel == '__uri') {
  24773.                     continue;
  24774.                 }
  24775.                 $this->config->set('default_channel', $channel);
  24776.                 $chan = &$reg->getChannel($channel);
  24777.                 if (PEAR::isError($chan)) {
  24778.                     return $this->raiseError($chan);
  24779.                 }
  24780.                 if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  24781.                       $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  24782.                     $dorest = true;
  24783.                     unset($remote);
  24784.                 } else {
  24785.                     $dorest = false;
  24786.                     $remote = &$this->config->getRemote($this->config);
  24787.                 }
  24788.                 $state = $this->config->get('preferred_state');
  24789.                 $installed = array_flip($reg->listPackages($channel));
  24790.                 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24791.                 if ($dorest) {
  24792.                     $rest = &$this->config->getREST('1.0', array());
  24793.                     $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
  24794.                 } else {
  24795.                     if (empty($state) || $state == 'any') {
  24796.                         $latest = $remote->call("package.listLatestReleases");
  24797.                     } else {
  24798.                         $latest = $remote->call("package.listLatestReleases", $state);
  24799.                     }
  24800.                 }
  24801.                 PEAR::staticPopErrorHandling();
  24802.                 if (PEAR::isError($latest) || !is_array($latest)) {
  24803.                     continue;
  24804.                 }
  24805.                 foreach ($latest as $package => $info) {
  24806.                     $package = strtolower($package);
  24807.                     if (!isset($installed[$package])) {
  24808.                         // skip packages we don't have installed
  24809.                         continue;
  24810.                     }
  24811.                     $inst_version = $reg->packageInfo($package, 'version', $channel);
  24812.                     if (version_compare("$info[version]", "$inst_version", "le")) {
  24813.                         // installed version is up-to-date
  24814.                         continue;
  24815.                     }
  24816.                     $params[] = $reg->parsedPackageNameToString(array('package' => $package,
  24817.                         'channel' => $channel));
  24818.                     $this->ui->outputData(array('data' => "Will upgrade $package"), $command);
  24819.                 }
  24820.             }
  24821.             $this->config->set('default_channel', $savechannel);
  24822.         }
  24823.         $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
  24824.         $errors = array();
  24825.         $downloaded = array();
  24826.         $downloaded = &$this->downloader->download($params);
  24827.         $errors = $this->downloader->getErrorMsgs();
  24828.         if (count($errors)) {
  24829.             foreach ($errors as $error) {
  24830.                 $err['data'][] = array($error);
  24831.             }
  24832.             $err['headline'] = 'Install Errors';
  24833.             $this->ui->outputData($err);
  24834.             if (!count($downloaded)) {
  24835.                 return $this->raiseError("$command failed");
  24836.             }
  24837.         }
  24838.         $data = array(
  24839.             'headline' => 'Packages that would be Installed'
  24840.         );
  24841.         if (isset($options['pretend'])) {
  24842.             foreach ($downloaded as $package) {
  24843.                 $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
  24844.             }
  24845.             $this->ui->outputData($data, 'pretend');
  24846.             return true;
  24847.         }
  24848.         $this->installer->setOptions($options);
  24849.         $this->installer->sortPackagesForInstall($downloaded);
  24850.         if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
  24851.             $this->raiseError($err->getMessage());
  24852.             return true;
  24853.         }
  24854.         $extrainfo = array();
  24855.         foreach ($downloaded as $param) {
  24856.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24857.             $info = $this->installer->install($param, $options);
  24858.             PEAR::staticPopErrorHandling();
  24859.             if (PEAR::isError($info)) {
  24860.                 $oldinfo = $info;
  24861.                 $pkg = &$param->getPackageFile();
  24862.                 if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
  24863.                     if (!($info = $pkg->installBinary($this->installer))) {
  24864.                         $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
  24865.                         continue;
  24866.                     }
  24867.                     // we just installed a different package than requested,
  24868.                     // let's change the param and info so that the rest of this works
  24869.                     $param = $info[0];
  24870.                     $info = $info[1];
  24871.                 }
  24872.             }
  24873.             if (is_array($info)) {
  24874.                 if ($param->getPackageType() == 'extsrc' ||
  24875.                       $param->getPackageType() == 'extbin') {
  24876.                     $pkg = &$param->getPackageFile();
  24877.                     if ($instbin = $pkg->getInstalledBinary()) {
  24878.                         $instpkg = &$reg->getPackage($instbin, $pkg->getChannel());
  24879.                     } else {
  24880.                         $instpkg = &$reg->getPackage($pkg->getPackage(), $pkg->getChannel());
  24881.                     }
  24882.                     foreach ($instpkg->getFilelist() as $name => $atts) {
  24883.                         $pinfo = pathinfo($atts['installed_as']);
  24884.                         if (!isset($pinfo['extension']) ||
  24885.                               in_array($pinfo['extension'], array('c', 'h'))) {
  24886.                             continue; // make sure we don't match php_blah.h
  24887.                         }
  24888.                         if ((strpos($pinfo['basename'], 'php_') === 0 &&
  24889.                               $pinfo['extension'] == 'dll') ||
  24890.                               // most unices
  24891.                               $pinfo['extension'] == 'so' ||
  24892.                               // hp-ux
  24893.                               $pinfo['extension'] == 'sl') {
  24894.                             $extrainfo[] = 'You should add "extension=' . $pinfo['basename']
  24895.                                 . '" to php.ini';
  24896.                             break;
  24897.                         }
  24898.                     }
  24899.                 }
  24900.                 if ($this->config->get('verbose') > 0) {
  24901.                     $channel = $param->getChannel();
  24902.                     $label = $reg->parsedPackageNameToString(
  24903.                         array(
  24904.                             'channel' => $channel,
  24905.                             'package' => $param->getPackage(),
  24906.                             'version' => $param->getVersion(),
  24907.                         ));
  24908.                     $out = array('data' => "$command ok: $label");
  24909.                     if (isset($info['release_warnings'])) {
  24910.                         $out['release_warnings'] = $info['release_warnings'];
  24911.                     }
  24912.                     $this->ui->outputData($out, $command);
  24913.                     if (!isset($options['register-only']) && !isset($options['offline'])) {
  24914.                         if ($this->config->isDefinedLayer('ftp')) {
  24915.                             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  24916.                             $info = $this->installer->ftpInstall($param);
  24917.                             PEAR::staticPopErrorHandling();
  24918.                             if (PEAR::isError($info)) {
  24919.                                 $this->ui->outputData($info->getMessage());
  24920.                                 $this->ui->outputData("remote install failed: $label");
  24921.                             } else {
  24922.                                 $this->ui->outputData("remote install ok: $label");
  24923.                             }
  24924.                         }
  24925.                     }
  24926.                 }
  24927.                 $deps = $param->getDeps();
  24928.                 if ($deps) {
  24929.                     if (isset($deps['group'])) {
  24930.                         $groups = $deps['group'];
  24931.                         if (!isset($groups[0])) {
  24932.                             $groups = array($groups);
  24933.                         }
  24934.                         foreach ($groups as $group) {
  24935.                             if ($group['attribs']['name'] == 'default') {
  24936.                                 // default group is always installed, unless the user
  24937.                                 // explicitly chooses to install another group
  24938.                                 continue;
  24939.                             }
  24940.                             $this->ui->outputData($param->getPackage() . ': Optional feature ' .
  24941.                                 $group['attribs']['name'] . ' available (' .
  24942.                                 $group['attribs']['hint'] . ')');
  24943.                         }
  24944.                         $extrainfo[] = 'To install use "pear install ' .
  24945.                             $reg->parsedPackageNameToString(
  24946.                                 array('package' => $param->getPackage(),
  24947.                                       'channel' => $param->getChannel()), true) .
  24948.                                   '#featurename"';
  24949.                     }
  24950.                 }
  24951.                 if (isset($options['installroot'])) {
  24952.                     $reg = &$this->config->getRegistry();
  24953.                 }
  24954.                 $pkg = &$reg->getPackage($param->getPackage(), $param->getChannel());
  24955.                 // $pkg may be NULL if install is a 'fake' install via --packagingroot
  24956.                 if (is_object($pkg)) {
  24957.                     $pkg->setConfig($this->config);
  24958.                     if ($list = $pkg->listPostinstallScripts()) {
  24959.                         $pn = $reg->parsedPackageNameToString(array('channel' =>
  24960.                            $param->getChannel(), 'package' => $param->getPackage()), true);
  24961.                         $extrainfo[] = $pn . ' has post-install scripts:';
  24962.                         foreach ($list as $file) {
  24963.                             $extrainfo[] = $file;
  24964.                         }
  24965.                         $extrainfo[] = 'Use "pear run-scripts ' . $pn . '" to run';
  24966.                         $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
  24967.                     }
  24968.                 }
  24969.             } else {
  24970.                 return $this->raiseError("$command failed");
  24971.             }
  24972.         }
  24973.         if (count($extrainfo)) {
  24974.             foreach ($extrainfo as $info) {
  24975.                 $this->ui->outputData($info);
  24976.             }
  24977.         }
  24978.         return true;
  24979.     }
  24980.  
  24981.     // }}}
  24982.     // {{{ doUninstall()
  24983.  
  24984.     function doUninstall($command, $options, $params)
  24985.     {
  24986.         if (empty($this->installer)) {
  24987.             $this->installer = &$this->getInstaller($this->ui);
  24988.         }
  24989.         if (isset($options['remoteconfig'])) {
  24990.             $e = $this->config->readFTPConfigFile($options['remoteconfig']);
  24991.             if (!PEAR::isError($e)) {
  24992.                 $this->installer->setConfig($this->config);
  24993.             }
  24994.         }
  24995.         if (sizeof($params) < 1) {
  24996.             return $this->raiseError("Please supply the package(s) you want to uninstall");
  24997.         }
  24998.         $reg = &$this->config->getRegistry();
  24999.         $newparams = array();
  25000.         $badparams = array();
  25001.         foreach ($params as $pkg) {
  25002.             $channel = $this->config->get('default_channel');
  25003.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  25004.             $parsed = $reg->parsePackageName($pkg, $channel);
  25005.             PEAR::staticPopErrorHandling();
  25006.             if (!$parsed || PEAR::isError($parsed)) {
  25007.                 $badparams[] = $pkg;
  25008.                 continue;
  25009.             }
  25010.             $package = $parsed['package'];
  25011.             $channel = $parsed['channel'];
  25012.             $info = &$reg->getPackage($package, $channel);
  25013.             if ($info === null &&
  25014.                  ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
  25015.                 // make sure this isn't a package that has flipped from pear to pecl but
  25016.                 // used a package.xml 1.0
  25017.                 $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
  25018.                 $info = &$reg->getPackage($package, $testc);
  25019.                 if ($info !== null) {
  25020.                     $channel = $testc;
  25021.                 }
  25022.             }
  25023.             if ($info === null) {
  25024.                 $badparams[] = $pkg;
  25025.             } else {
  25026.                 $newparams[] = &$info;
  25027.                 // check for binary packages (this is an alias for those packages if so)
  25028.                 if ($installedbinary = $info->getInstalledBinary()) {
  25029.                     $this->ui->log('adding binary package ' .
  25030.                         $reg->parsedPackageNameToString(array('channel' => $channel,
  25031.                             'package' => $installedbinary), true));
  25032.                     $newparams[] = &$reg->getPackage($installedbinary, $channel);
  25033.                 }
  25034.                 // add the contents of a dependency group to the list of installed packages
  25035.                 if (isset($parsed['group'])) {
  25036.                     $group = $info->getDependencyGroup($parsed['group']);
  25037.                     if ($group) {
  25038.                         $installed = &$reg->getInstalledGroup($group);
  25039.                         if ($installed) {
  25040.                             foreach ($installed as $i => $p) {
  25041.                                 $newparams[] = &$installed[$i];
  25042.                             }
  25043.                         }
  25044.                     }
  25045.                 }
  25046.             }
  25047.         }
  25048.         $err = $this->installer->sortPackagesForUninstall($newparams);
  25049.         if (PEAR::isError($err)) {
  25050.             $this->ui->outputData($err->getMessage(), $command);
  25051.             return true;
  25052.         }
  25053.         $params = $newparams;
  25054.         // twist this to use it to check on whether dependent packages are also being uninstalled
  25055.         // for circular dependencies like subpackages
  25056.         $this->installer->setUninstallPackages($newparams);
  25057.         $params = array_merge($params, $badparams);
  25058.         foreach ($params as $pkg) {
  25059.             $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  25060.             if ($err = $this->installer->uninstall($pkg, $options)) {
  25061.                 $this->installer->popErrorHandling();
  25062.                 if (PEAR::isError($err)) {
  25063.                     $this->ui->outputData($err->getMessage(), $command);
  25064.                     continue;
  25065.                 }
  25066.                 $savepkg = $pkg;
  25067.                 if ($this->config->get('verbose') > 0) {
  25068.                     if (is_object($pkg)) {
  25069.                         $pkg = $reg->parsedPackageNameToString($pkg);
  25070.                     }
  25071.                     $this->ui->outputData("uninstall ok: $pkg", $command);
  25072.                 }
  25073.                 if (!isset($options['offline']) && is_object($savepkg) &&
  25074.                       defined('PEAR_REMOTEINSTALL_OK')) {
  25075.                     if ($this->config->isDefinedLayer('ftp')) {
  25076.                         $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
  25077.                         $info = $this->installer->ftpUninstall($savepkg);
  25078.                         $this->installer->popErrorHandling();
  25079.                         if (PEAR::isError($info)) {
  25080.                             $this->ui->outputData($info->getMessage());
  25081.                             $this->ui->outputData("remote uninstall failed: $pkg");
  25082.                         } else {
  25083.                             $this->ui->outputData("remote uninstall ok: $pkg");
  25084.                         }
  25085.                     }
  25086.                 }
  25087.             } else {
  25088.                 $this->installer->popErrorHandling();
  25089.                 if (is_object($pkg)) {
  25090.                     $pkg = $reg->parsedPackageNameToString($pkg);
  25091.                 }
  25092.                 return $this->raiseError("uninstall failed: $pkg");
  25093.             }
  25094.         }
  25095.         return true;
  25096.     }
  25097.  
  25098.     // }}}
  25099.  
  25100.  
  25101.     // }}}
  25102.     // {{{ doBundle()
  25103.     /*
  25104.     (cox) It just downloads and untars the package, does not do
  25105.             any check that the PEAR_Installer::_installFile() does.
  25106.     */
  25107.  
  25108.     function doBundle($command, $options, $params)
  25109.     {
  25110.         $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true,
  25111.             'soft' => true), $this->config);
  25112.         $reg = &$this->config->getRegistry();
  25113.         if (sizeof($params) < 1) {
  25114.             return $this->raiseError("Please supply the package you want to bundle");
  25115.         }
  25116.  
  25117.         if (isset($options['destination'])) {
  25118.             if (!is_dir($options['destination'])) {
  25119.                 System::mkdir('-p ' . $options['destination']);
  25120.             }
  25121.             $dest = realpath($options['destination']);
  25122.         } else {
  25123.             $pwd = getcwd();
  25124.             if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
  25125.                 $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
  25126.             } else {
  25127.                 $dest = $pwd;
  25128.             }
  25129.         }
  25130.         $downloader->setDownloadDir($dest);
  25131.         $result = &$downloader->download(array($params[0]));
  25132.         if (PEAR::isError($result)) {
  25133.             return $result;
  25134.         }
  25135.         $pkgfile = &$result[0]->getPackageFile();
  25136.         $pkgname = $pkgfile->getName();
  25137.         $pkgversion = $pkgfile->getVersion();
  25138.  
  25139.         // Unpacking -------------------------------------------------
  25140.         $dest .= DIRECTORY_SEPARATOR . $pkgname;
  25141.         $orig = $pkgname . '-' . $pkgversion;
  25142.  
  25143.         $tar = &new Archive_Tar($pkgfile->getArchiveFile());
  25144.         if (!@$tar->extractModify($dest, $orig)) {
  25145.             return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
  25146.         }
  25147.         $this->ui->outputData("Package ready at '$dest'");
  25148.     // }}}
  25149.     }
  25150.  
  25151.     // }}}
  25152.  
  25153.     function doRunScripts($command, $options, $params)
  25154.     {
  25155.         if (!isset($params[0])) {
  25156.             return $this->raiseError('run-scripts expects 1 parameter: a package name');
  25157.         }
  25158.         $reg = &$this->config->getRegistry();
  25159.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  25160.         $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  25161.         PEAR::staticPopErrorHandling();
  25162.         if (PEAR::isError($parsed)) {
  25163.             return $this->raiseError($parsed);
  25164.         }
  25165.         $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
  25166.         if (is_object($package)) {
  25167.             $package->setConfig($this->config);
  25168.             $package->runPostinstallScripts();
  25169.         } else {
  25170.             return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
  25171.         }
  25172.         $this->ui->outputData('Install scripts complete', $command);
  25173.         return true;
  25174.     }
  25175. }
  25176. ?>
  25177. PEAR-1.4.11/PEAR/Command/Mirror.xml100644   1750   1750        1151 10470570063  11650 <commands version="1.0">
  25178.  <download-all>
  25179.   <summary>Downloads each available package from the default channel</summary>
  25180.   <function>doDownloadAll</function>
  25181.   <shortcut>da</shortcut>
  25182.   <options>
  25183.    <channel>
  25184.     <shortopt>c</shortopt>
  25185.     <doc>specify a channel other than the default channel</doc>
  25186.     <arg>CHAN</arg>
  25187.    </channel>
  25188.   </options>
  25189.   <doc>
  25190. Requests a list of available packages from the default channel ({config default_channel})
  25191. and downloads them to current working directory.  Note: only
  25192. packages within preferred_state ({config preferred_state}) will be downloaded</doc>
  25193.  </download-all>
  25194. </commands>PEAR-1.4.11/PEAR/Command/Mirror.php100644   1750   1750       12222 10470570063  11660 <?php
  25195. /**
  25196.  * PEAR_Command_Mirror (download-all command)
  25197.  *
  25198.  * PHP versions 4 and 5
  25199.  *
  25200.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  25201.  * that is available through the world-wide-web at the following URI:
  25202.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  25203.  * the PHP License and are unable to obtain it through the web, please
  25204.  * send a note to license@php.net so we can mail you a copy immediately.
  25205.  *
  25206.  * @category   pear
  25207.  * @package    PEAR
  25208.  * @author     Alexander Merz <alexmerz@php.net>
  25209.  * @copyright  1997-2006 The PHP Group
  25210.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25211.  * @version    CVS: $Id: Mirror.php,v 1.18 2006/03/02 18:14:13 cellog Exp $
  25212.  * @link       http://pear.php.net/package/PEAR
  25213.  * @since      File available since Release 1.2.0
  25214.  */
  25215.  
  25216. /**
  25217.  * base class
  25218.  */
  25219. require_once 'PEAR/Command/Common.php';
  25220.  
  25221. /**
  25222.  * PEAR commands for providing file mirrors
  25223.  *
  25224.  * @category   pear
  25225.  * @package    PEAR
  25226.  * @author     Alexander Merz <alexmerz@php.net>
  25227.  * @copyright  1997-2006 The PHP Group
  25228.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25229.  * @version    Release: 1.4.11
  25230.  * @link       http://pear.php.net/package/PEAR
  25231.  * @since      Class available since Release 1.2.0
  25232.  */
  25233. class PEAR_Command_Mirror extends PEAR_Command_Common
  25234. {
  25235.     // {{{ properties
  25236.  
  25237.     var $commands = array(
  25238.         'download-all' => array(
  25239.             'summary' => 'Downloads each available package from the default channel',
  25240.             'function' => 'doDownloadAll',
  25241.             'shortcut' => 'da',
  25242.             'options' => array(
  25243.                 'channel' =>
  25244.                     array(
  25245.                     'shortopt' => 'c',
  25246.                     'doc' => 'specify a channel other than the default channel',
  25247.                     'arg' => 'CHAN',
  25248.                     ),
  25249.                 ),
  25250.             'doc' => '
  25251. Requests a list of available packages from the default channel ({config default_channel})
  25252. and downloads them to current working directory.  Note: only
  25253. packages within preferred_state ({config preferred_state}) will be downloaded'
  25254.             ),
  25255.         );
  25256.  
  25257.     // }}}
  25258.  
  25259.     // {{{ constructor
  25260.  
  25261.     /**
  25262.      * PEAR_Command_Mirror constructor.
  25263.      *
  25264.      * @access public
  25265.      * @param object PEAR_Frontend a reference to an frontend
  25266.      * @param object PEAR_Config a reference to the configuration data
  25267.      */
  25268.     function PEAR_Command_Mirror(&$ui, &$config)
  25269.     {
  25270.         parent::PEAR_Command_Common($ui, $config);
  25271.     }
  25272.  
  25273.     // }}}
  25274.  
  25275.     /**
  25276.      * For unit-testing
  25277.      */
  25278.     function &factory($a)
  25279.     {
  25280.         $a = &PEAR_Command::factory($a, $this->config);
  25281.         return $a;
  25282.     }
  25283.  
  25284.     // {{{ doDownloadAll()
  25285.     /**
  25286.     * retrieves a list of avaible Packages from master server
  25287.     * and downloads them
  25288.     *
  25289.     * @access public
  25290.     * @param string $command the command
  25291.     * @param array $options the command options before the command
  25292.     * @param array $params the stuff after the command name
  25293.     * @return bool true if succesful
  25294.     * @throw PEAR_Error 
  25295.     */
  25296.     function doDownloadAll($command, $options, $params)
  25297.     {
  25298.         $savechannel = $this->config->get('default_channel');
  25299.         $reg = &$this->config->getRegistry();
  25300.         $channel = isset($options['channel']) ? $options['channel'] :
  25301.             $this->config->get('default_channel');
  25302.         if (!$reg->channelExists($channel)) {
  25303.             $this->config->set('default_channel', $savechannel);
  25304.             return $this->raiseError('Channel "' . $channel . '" does not exist');
  25305.         }
  25306.         $this->config->set('default_channel', $channel);
  25307.         $this->ui->outputData('Using Channel ' . $this->config->get('default_channel'));
  25308.         $chan = $reg->getChannel($channel);
  25309.         if (PEAR::isError($chan)) {
  25310.             return $this->raiseError($chan);
  25311.         }
  25312.         if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
  25313.               $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
  25314.             $rest = &$this->config->getREST('1.0', array());
  25315.             $remoteInfo = array_flip($rest->listPackages($base));
  25316.         } else {
  25317.             $remote = &$this->config->getRemote();
  25318.             $stable = ($this->config->get('preferred_state') == 'stable');
  25319.             $remoteInfo = $remote->call("package.listAll", true, $stable, false);
  25320.         }
  25321.         if (PEAR::isError($remoteInfo)) {
  25322.             return $remoteInfo;
  25323.         }
  25324.         $cmd = &$this->factory("download");
  25325.         if (PEAR::isError($cmd)) {
  25326.             return $cmd;
  25327.         }
  25328.         $this->ui->outputData('Using Preferred State of ' .
  25329.             $this->config->get('preferred_state'));
  25330.         $this->ui->outputData('Gathering release information, please wait...');
  25331.         /**
  25332.          * Error handling not necessary, because already done by 
  25333.          * the download command
  25334.          */
  25335.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  25336.         $err = $cmd->run('download', array('downloadonly' => true), array_keys($remoteInfo));
  25337.         PEAR::staticPopErrorHandling();
  25338.         $this->config->set('default_channel', $savechannel);
  25339.         if (PEAR::isError($err)) {
  25340.             $this->ui->outputData($err->getMessage());
  25341.         }
  25342.         return true;
  25343.     }
  25344.  
  25345.     // }}}
  25346. }
  25347. PEAR-1.4.11/PEAR/Command/Package.xml100644   1750   1750       13206 10470570063  11755 <commands version="1.0">
  25348.  <package>
  25349.   <summary>Build Package</summary>
  25350.   <function>doPackage</function>
  25351.   <shortcut>p</shortcut>
  25352.   <options>
  25353.    <nocompress>
  25354.     <shortopt>Z</shortopt>
  25355.     <doc>Do not gzip the package file</doc>
  25356.    </nocompress>
  25357.    <showname>
  25358.     <shortopt>n</shortopt>
  25359.     <doc>Print the name of the packaged file.</doc>
  25360.    </showname>
  25361.   </options>
  25362.   <doc>[descfile] [descfile2]
  25363. Creates a PEAR package from its description file (usually called
  25364. package.xml).  If a second packagefile is passed in, then
  25365. the packager will check to make sure that one is a package.xml
  25366. version 1.0, and the other is a package.xml version 2.0.  The
  25367. package.xml version 1.0 will be saved as "package.xml" in the archive,
  25368. and the other as "package2.xml" in the archive"
  25369. </doc>
  25370.  </package>
  25371.  <package-validate>
  25372.   <summary>Validate Package Consistency</summary>
  25373.   <function>doPackageValidate</function>
  25374.   <shortcut>pv</shortcut>
  25375.   <options />
  25376.   <doc>
  25377. </doc>
  25378.  </package-validate>
  25379.  <cvsdiff>
  25380.   <summary>Run a "cvs diff" for all files in a package</summary>
  25381.   <function>doCvsDiff</function>
  25382.   <shortcut>cd</shortcut>
  25383.   <options>
  25384.    <quiet>
  25385.     <shortopt>q</shortopt>
  25386.     <doc>Be quiet</doc>
  25387.    </quiet>
  25388.    <reallyquiet>
  25389.     <shortopt>Q</shortopt>
  25390.     <doc>Be really quiet</doc>
  25391.    </reallyquiet>
  25392.    <date>
  25393.     <shortopt>D</shortopt>
  25394.     <doc>Diff against revision of DATE</doc>
  25395.     <arg>DATE</arg>
  25396.    </date>
  25397.    <release>
  25398.     <shortopt>R</shortopt>
  25399.     <doc>Diff against tag for package release REL</doc>
  25400.     <arg>REL</arg>
  25401.    </release>
  25402.    <revision>
  25403.     <shortopt>r</shortopt>
  25404.     <doc>Diff against revision REV</doc>
  25405.     <arg>REV</arg>
  25406.    </revision>
  25407.    <context>
  25408.     <shortopt>c</shortopt>
  25409.     <doc>Generate context diff</doc>
  25410.    </context>
  25411.    <unified>
  25412.     <shortopt>u</shortopt>
  25413.     <doc>Generate unified diff</doc>
  25414.    </unified>
  25415.    <ignore-case>
  25416.     <shortopt>i</shortopt>
  25417.     <doc>Ignore case, consider upper- and lower-case letters equivalent</doc>
  25418.    </ignore-case>
  25419.    <ignore-whitespace>
  25420.     <shortopt>b</shortopt>
  25421.     <doc>Ignore changes in amount of white space</doc>
  25422.    </ignore-whitespace>
  25423.    <ignore-blank-lines>
  25424.     <shortopt>B</shortopt>
  25425.     <doc>Ignore changes that insert or delete blank lines</doc>
  25426.    </ignore-blank-lines>
  25427.    <brief>
  25428.     <doc>Report only whether the files differ, no details</doc>
  25429.    </brief>
  25430.    <dry-run>
  25431.     <shortopt>n</shortopt>
  25432.     <doc>Don't do anything, just pretend</doc>
  25433.    </dry-run>
  25434.   </options>
  25435.   <doc><package.xml>
  25436. Compares all the files in a package.  Without any options, this
  25437. command will compare the current code with the last checked-in code.
  25438. Using the -r or -R option you may compare the current code with that
  25439. of a specific release.
  25440. </doc>
  25441.  </cvsdiff>
  25442.  <cvstag>
  25443.   <summary>Set CVS Release Tag</summary>
  25444.   <function>doCvsTag</function>
  25445.   <shortcut>ct</shortcut>
  25446.   <options>
  25447.    <quiet>
  25448.     <shortopt>q</shortopt>
  25449.     <doc>Be quiet</doc>
  25450.    </quiet>
  25451.    <reallyquiet>
  25452.     <shortopt>Q</shortopt>
  25453.     <doc>Be really quiet</doc>
  25454.    </reallyquiet>
  25455.    <slide>
  25456.     <shortopt>F</shortopt>
  25457.     <doc>Move (slide) tag if it exists</doc>
  25458.    </slide>
  25459.    <delete>
  25460.     <shortopt>d</shortopt>
  25461.     <doc>Remove tag</doc>
  25462.    </delete>
  25463.    <dry-run>
  25464.     <shortopt>n</shortopt>
  25465.     <doc>Don't do anything, just pretend</doc>
  25466.    </dry-run>
  25467.   </options>
  25468.   <doc><package.xml>
  25469. Sets a CVS tag on all files in a package.  Use this command after you have
  25470. packaged a distribution tarball with the "package" command to tag what
  25471. revisions of what files were in that release.  If need to fix something
  25472. after running cvstag once, but before the tarball is released to the public,
  25473. use the "slide" option to move the release tag.
  25474. </doc>
  25475.  </cvstag>
  25476.  <package-dependencies>
  25477.   <summary>Show package dependencies</summary>
  25478.   <function>doPackageDependencies</function>
  25479.   <shortcut>pd</shortcut>
  25480.   <options />
  25481.   <doc>
  25482. List all dependencies the package has.</doc>
  25483.  </package-dependencies>
  25484.  <sign>
  25485.   <summary>Sign a package distribution file</summary>
  25486.   <function>doSign</function>
  25487.   <shortcut>si</shortcut>
  25488.   <options />
  25489.   <doc><package-file>
  25490. Signs a package distribution (.tar or .tgz) file with GnuPG.</doc>
  25491.  </sign>
  25492.  <makerpm>
  25493.   <summary>Builds an RPM spec file from a PEAR package</summary>
  25494.   <function>doMakeRPM</function>
  25495.   <shortcut>rpm</shortcut>
  25496.   <options>
  25497.    <spec-template>
  25498.     <shortopt>t</shortopt>
  25499.     <arg>FILE</arg>
  25500.     <doc>Use FILE as RPM spec file template</doc>
  25501.    </spec-template>
  25502.    <rpm-pkgname>
  25503.     <shortopt>p</shortopt>
  25504.     <arg>FORMAT</arg>
  25505.     <doc>Use FORMAT as format string for RPM package name, %s is replaced
  25506. by the PEAR package name, defaults to "PEAR::%s".</doc>
  25507.    </rpm-pkgname>
  25508.   </options>
  25509.   <doc><package-file>
  25510.  
  25511. Creates an RPM .spec file for wrapping a PEAR package inside an RPM
  25512. package.  Intended to be used from the SPECS directory, with the PEAR
  25513. package tarball in the SOURCES directory:
  25514.  
  25515. $ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
  25516. Wrote RPM spec file PEAR::Net_Geo-1.0.spec
  25517. $ rpm -bb PEAR::Net_Socket-1.0.spec
  25518. ...
  25519. Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
  25520. </doc>
  25521.  </makerpm>
  25522.  <convert>
  25523.   <summary>Convert a package.xml 1.0 to package.xml 2.0 format</summary>
  25524.   <function>doConvert</function>
  25525.   <shortcut>c2</shortcut>
  25526.   <options>
  25527.    <flat>
  25528.     <shortopt>f</shortopt>
  25529.     <doc>do not beautify the filelist.</doc>
  25530.    </flat>
  25531.   </options>
  25532.   <doc>[descfile] [descfile2]
  25533. Converts a package.xml in 1.0 format into a package.xml
  25534. in 2.0 format.  The new file will be named package2.xml by default,
  25535. and package.xml will be used as the old file by default.
  25536. This is not the most intelligent conversion, and should only be
  25537. used for automated conversion or learning the format.
  25538. </doc>
  25539.  </convert>
  25540. </commands>
  25541. PEAR-1.4.11/PEAR/Command/Package.php100644   1750   1750      134626 10470570063  11776 <?php
  25542. /**
  25543.  * PEAR_Command_Package (package, package-validate, cvsdiff, cvstag, package-dependencies,
  25544.  * sign, makerpm, convert commands)
  25545.  *
  25546.  * PHP versions 4 and 5
  25547.  *
  25548.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  25549.  * that is available through the world-wide-web at the following URI:
  25550.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  25551.  * the PHP License and are unable to obtain it through the web, please
  25552.  * send a note to license@php.net so we can mail you a copy immediately.
  25553.  *
  25554.  * @category   pear
  25555.  * @package    PEAR
  25556.  * @author     Stig Bakken <ssb@php.net>
  25557.  * @author     Martin Jansen <mj@php.net>
  25558.  * @author     Greg Beaver <cellog@php.net>
  25559.  * @copyright  1997-2006 The PHP Group
  25560.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25561.  * @version    CVS: $Id: Package.php,v 1.119.2.1 2006/06/07 23:39:22 pajoye Exp $
  25562.  * @link       http://pear.php.net/package/PEAR
  25563.  * @since      File available since Release 0.1
  25564.  */
  25565.  
  25566. /**
  25567.  * base class
  25568.  */
  25569. require_once 'PEAR/Command/Common.php';
  25570.  
  25571. /**
  25572.  * PEAR commands for login/logout
  25573.  *
  25574.  * @category   pear
  25575.  * @package    PEAR
  25576.  * @author     Stig Bakken <ssb@php.net>
  25577.  * @author     Martin Jansen <mj@php.net>
  25578.  * @author     Greg Beaver <cellog@php.net>
  25579.  * @copyright  1997-2006 The PHP Group
  25580.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  25581.  * @version    Release: @package_version@
  25582.  * @link       http://pear.php.net/package/PEAR
  25583.  * @since      Class available since Release 0.1
  25584.  */
  25585.  
  25586. class PEAR_Command_Package extends PEAR_Command_Common
  25587. {
  25588.     // {{{ properties
  25589.  
  25590.     var $commands = array(
  25591.         'package' => array(
  25592.             'summary' => 'Build Package',
  25593.             'function' => 'doPackage',
  25594.             'shortcut' => 'p',
  25595.             'options' => array(
  25596.                 'nocompress' => array(
  25597.                     'shortopt' => 'Z',
  25598.                     'doc' => 'Do not gzip the package file'
  25599.                     ),
  25600.                 'showname' => array(
  25601.                     'shortopt' => 'n',
  25602.                     'doc' => 'Print the name of the packaged file.',
  25603.                     ),
  25604.                 ),
  25605.             'doc' => '[descfile] [descfile2]
  25606. Creates a PEAR package from its description file (usually called
  25607. package.xml).  If a second packagefile is passed in, then
  25608. the packager will check to make sure that one is a package.xml
  25609. version 1.0, and the other is a package.xml version 2.0.  The
  25610. package.xml version 1.0 will be saved as "package.xml" in the archive,
  25611. and the other as "package2.xml" in the archive"
  25612. '
  25613.             ),
  25614.         'package-validate' => array(
  25615.             'summary' => 'Validate Package Consistency',
  25616.             'function' => 'doPackageValidate',
  25617.             'shortcut' => 'pv',
  25618.             'options' => array(),
  25619.             'doc' => '
  25620. ',
  25621.             ),
  25622.         'cvsdiff' => array(
  25623.             'summary' => 'Run a "cvs diff" for all files in a package',
  25624.             'function' => 'doCvsDiff',
  25625.             'shortcut' => 'cd',
  25626.             'options' => array(
  25627.                 'quiet' => array(
  25628.                     'shortopt' => 'q',
  25629.                     'doc' => 'Be quiet',
  25630.                     ),
  25631.                 'reallyquiet' => array(
  25632.                     'shortopt' => 'Q',
  25633.                     'doc' => 'Be really quiet',
  25634.                     ),
  25635.                 'date' => array(
  25636.                     'shortopt' => 'D',
  25637.                     'doc' => 'Diff against revision of DATE',
  25638.                     'arg' => 'DATE',
  25639.                     ),
  25640.                 'release' => array(
  25641.                     'shortopt' => 'R',
  25642.                     'doc' => 'Diff against tag for package release REL',
  25643.                     'arg' => 'REL',
  25644.                     ),
  25645.                 'revision' => array(
  25646.                     'shortopt' => 'r',
  25647.                     'doc' => 'Diff against revision REV',
  25648.                     'arg' => 'REV',
  25649.                     ),
  25650.                 'context' => array(
  25651.                     'shortopt' => 'c',
  25652.                     'doc' => 'Generate context diff',
  25653.                     ),
  25654.                 'unified' => array(
  25655.                     'shortopt' => 'u',
  25656.                     'doc' => 'Generate unified diff',
  25657.                     ),
  25658.                 'ignore-case' => array(
  25659.                     'shortopt' => 'i',
  25660.                     'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
  25661.                     ),
  25662.                 'ignore-whitespace' => array(
  25663.                     'shortopt' => 'b',
  25664.                     'doc' => 'Ignore changes in amount of white space',
  25665.                     ),
  25666.                 'ignore-blank-lines' => array(
  25667.                     'shortopt' => 'B',
  25668.                     'doc' => 'Ignore changes that insert or delete blank lines',
  25669.                     ),
  25670.                 'brief' => array(
  25671.                     'doc' => 'Report only whether the files differ, no details',
  25672.                     ),
  25673.                 'dry-run' => array(
  25674.                     'shortopt' => 'n',
  25675.                     'doc' => 'Don\'t do anything, just pretend',
  25676.                     ),
  25677.                 ),
  25678.             'doc' => '<package.xml>
  25679. Compares all the files in a package.  Without any options, this
  25680. command will compare the current code with the last checked-in code.
  25681. Using the -r or -R option you may compare the current code with that
  25682. of a specific release.
  25683. ',
  25684.             ),
  25685.         'cvstag' => array(
  25686.             'summary' => 'Set CVS Release Tag',
  25687.             'function' => 'doCvsTag',
  25688.             'shortcut' => 'ct',
  25689.             'options' => array(
  25690.                 'quiet' => array(
  25691.                     'shortopt' => 'q',
  25692.                     'doc' => 'Be quiet',
  25693.                     ),
  25694.                 'reallyquiet' => array(
  25695.                     'shortopt' => 'Q',
  25696.                     'doc' => 'Be really quiet',
  25697.                     ),
  25698.                 'slide' => array(
  25699.                     'shortopt' => 'F',
  25700.                     'doc' => 'Move (slide) tag if it exists',
  25701.                     ),
  25702.                 'delete' => array(
  25703.                     'shortopt' => 'd',
  25704.                     'doc' => 'Remove tag',
  25705.                     ),
  25706.                 'dry-run' => array(
  25707.                     'shortopt' => 'n',
  25708.                     'doc' => 'Don\'t do anything, just pretend',
  25709.                     ),
  25710.                 ),
  25711.             'doc' => '<package.xml> [files...]
  25712. Sets a CVS tag on all files in a package.  Use this command after you have
  25713. packaged a distribution tarball with the "package" command to tag what
  25714. revisions of what files were in that release.  If need to fix something
  25715. after running cvstag once, but before the tarball is released to the public,
  25716. use the "slide" option to move the release tag.
  25717.  
  25718. to include files (such as a second package.xml, or tests not included in the
  25719. release), pass them as additional parameters.
  25720. ',
  25721.             ),
  25722.         'package-dependencies' => array(
  25723.             'summary' => 'Show package dependencies',
  25724.             'function' => 'doPackageDependencies',
  25725.             'shortcut' => 'pd',
  25726.             'options' => array(),
  25727.             'doc' => '
  25728. List all dependencies the package has.'
  25729.             ),
  25730.         'sign' => array(
  25731.             'summary' => 'Sign a package distribution file',
  25732.             'function' => 'doSign',
  25733.             'shortcut' => 'si',
  25734.             'options' => array(),
  25735.             'doc' => '<package-file>
  25736. Signs a package distribution (.tar or .tgz) file with GnuPG.',
  25737.             ),
  25738.         'makerpm' => array(
  25739.             'summary' => 'Builds an RPM spec file from a PEAR package',
  25740.             'function' => 'doMakeRPM',
  25741.             'shortcut' => 'rpm',
  25742.             'options' => array(
  25743.                 'spec-template' => array(
  25744.                     'shortopt' => 't',
  25745.                     'arg' => 'FILE',
  25746.                     'doc' => 'Use FILE as RPM spec file template'
  25747.                     ),
  25748.                 'rpm-pkgname' => array(
  25749.                     'shortopt' => 'p',
  25750.                     'arg' => 'FORMAT',
  25751.                     'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
  25752. by the PEAR package name, defaults to "PEAR::%s".',
  25753.                     ),
  25754.                 ),
  25755.             'doc' => '<package-file>
  25756.  
  25757. Creates an RPM .spec file for wrapping a PEAR package inside an RPM
  25758. package.  Intended to be used from the SPECS directory, with the PEAR
  25759. package tarball in the SOURCES directory:
  25760.  
  25761. $ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
  25762. Wrote RPM spec file PEAR::Net_Geo-1.0.spec
  25763. $ rpm -bb PEAR::Net_Socket-1.0.spec
  25764. ...
  25765. Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
  25766. ',
  25767.             ),
  25768.         'convert' => array(
  25769.             'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
  25770.             'function' => 'doConvert',
  25771.             'shortcut' => 'c2',
  25772.             'options' => array(
  25773.                 'flat' => array(
  25774.                     'shortopt' => 'f',
  25775.                     'doc' => 'do not beautify the filelist.',
  25776.                     ),
  25777.                 ),
  25778.             'doc' => '[descfile] [descfile2]
  25779. Converts a package.xml in 1.0 format into a package.xml
  25780. in 2.0 format.  The new file will be named package2.xml by default,
  25781. and package.xml will be used as the old file by default.
  25782. This is not the most intelligent conversion, and should only be
  25783. used for automated conversion or learning the format.
  25784. '
  25785.             ),
  25786.         );
  25787.  
  25788.     var $output;
  25789.  
  25790.     // }}}
  25791.     // {{{ constructor
  25792.  
  25793.     /**
  25794.      * PEAR_Command_Package constructor.
  25795.      *
  25796.      * @access public
  25797.      */
  25798.     function PEAR_Command_Package(&$ui, &$config)
  25799.     {
  25800.         parent::PEAR_Command_Common($ui, $config);
  25801.     }
  25802.  
  25803.     // }}}
  25804.  
  25805.     // {{{ _displayValidationResults()
  25806.  
  25807.     function _displayValidationResults($err, $warn, $strict = false)
  25808.     {
  25809.         foreach ($err as $e) {
  25810.             $this->output .= "Error: $e\n";
  25811.         }
  25812.         foreach ($warn as $w) {
  25813.             $this->output .= "Warning: $w\n";
  25814.         }
  25815.         $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n",
  25816.                                        sizeof($err), sizeof($warn));
  25817.         if ($strict && sizeof($err) > 0) {
  25818.             $this->output .= "Fix these errors and try again.";
  25819.             return false;
  25820.         }
  25821.         return true;
  25822.     }
  25823.  
  25824.     // }}}
  25825.     function &getPackager()
  25826.     {
  25827.         if (!class_exists('PEAR_Packager')) {
  25828.             require_once 'PEAR/Packager.php';
  25829.         }
  25830.         $a = &new PEAR_Packager;
  25831.         return $a;
  25832.     }
  25833.  
  25834.     function &getPackageFile($config, $debug = false, $tmpdir = null)
  25835.     {
  25836.         if (!class_exists('PEAR_Common')) {
  25837.             require_once 'PEAR/Common.php';
  25838.         }
  25839.         if (!class_exists('PEAR/PackageFile.php')) {
  25840.             require_once 'PEAR/PackageFile.php';
  25841.         }
  25842.         $a = &new PEAR_PackageFile($config, $debug, $tmpdir);
  25843.         $common = new PEAR_Common;
  25844.         $common->ui = $this->ui;
  25845.         $a->setLogger($common);
  25846.         return $a;
  25847.     }
  25848.     // {{{ doPackage()
  25849.  
  25850.     function doPackage($command, $options, $params)
  25851.     {
  25852.         $this->output = '';
  25853.         $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
  25854.         $pkg2 = isset($params[1]) ? $params[1] : null;
  25855.         if (!$pkg2 && !isset($params[0])) {
  25856.             if (file_exists('package2.xml')) {
  25857.                 $pkg2 = 'package2.xml';
  25858.             }
  25859.         }
  25860.         $packager = &$this->getPackager();
  25861.         $compress = empty($options['nocompress']) ? true : false;
  25862.         $result = $packager->package($pkginfofile, $compress, $pkg2);
  25863.         if (PEAR::isError($result)) {
  25864.             return $this->raiseError($result);
  25865.         }
  25866.         // Don't want output, only the package file name just created
  25867.         if (isset($options['showname'])) {
  25868.             $this->output = $result;
  25869.         }
  25870.         if ($this->output) {
  25871.             $this->ui->outputData($this->output, $command);
  25872.         }
  25873.         return true;
  25874.     }
  25875.  
  25876.     // }}}
  25877.     // {{{ doPackageValidate()
  25878.  
  25879.     function doPackageValidate($command, $options, $params)
  25880.     {
  25881.         $this->output = '';
  25882.         if (sizeof($params) < 1) {
  25883.             $params[0] = "package.xml";
  25884.         }
  25885.         $obj = &$this->getPackageFile($this->config, $this->_debug);
  25886.         $obj->rawReturn();
  25887.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  25888.         $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
  25889.         if (PEAR::isError($info)) {
  25890.             $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
  25891.         } else {
  25892.             $archive = $info->getArchiveFile();
  25893.             $tar = &new Archive_Tar($archive);
  25894.             $tar->extract(dirname($info->getPackageFile()));
  25895.             $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
  25896.                 $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
  25897.                 basename($info->getPackageFile()));
  25898.         }
  25899.         PEAR::staticPopErrorHandling();
  25900.         if (PEAR::isError($info)) {
  25901.             return $this->raiseError($info);
  25902.         }
  25903.         $valid = false;
  25904.         if ($info->getPackagexmlVersion() == '2.0') {
  25905.             if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
  25906.                 $info->flattenFileList();
  25907.                 $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
  25908.             }
  25909.         } else {
  25910.             $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
  25911.         }
  25912.         $err = array();
  25913.         $warn = array();
  25914.         if (!$valid) {
  25915.             foreach ($info->getValidationWarnings() as $error) {
  25916.                 if ($error['level'] == 'warning') {
  25917.                     $warn[] = $error['message'];
  25918.                 } else {
  25919.                     $err[] = $error['message'];
  25920.                 }
  25921.             }
  25922.         }
  25923.         $this->_displayValidationResults($err, $warn);
  25924.         $this->ui->outputData($this->output, $command);
  25925.         return true;
  25926.     }
  25927.  
  25928.     // }}}
  25929.     // {{{ doCvsTag()
  25930.  
  25931.     function doCvsTag($command, $options, $params)
  25932.     {
  25933.         $this->output = '';
  25934.         $_cmd = $command;
  25935.         if (sizeof($params) < 1) {
  25936.             $help = $this->getHelp($command);
  25937.             return $this->raiseError("$command: missing parameter: $help[0]");
  25938.         }
  25939.         $obj = &$this->getPackageFile($this->config, $this->_debug);
  25940.         $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  25941.         if (PEAR::isError($info)) {
  25942.             return $this->raiseError($info);
  25943.         }
  25944.         $err = $warn = array();
  25945.         if (!$info->validate()) {
  25946.             foreach ($info->getValidationWarnings() as $error) {
  25947.                 if ($error['level'] == 'warning') {
  25948.                     $warn[] = $error['message'];
  25949.                 } else {
  25950.                     $err[] = $error['message'];
  25951.                 }
  25952.             }
  25953.         }
  25954.         if (!$this->_displayValidationResults($err, $warn, true)) {
  25955.             $this->ui->outputData($this->output, $command);
  25956.             return $this->raiseError('CVS tag failed');
  25957.         }
  25958.         $version = $info->getVersion();
  25959.         $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
  25960.         $cvstag = "RELEASE_$cvsversion";
  25961.         $files = array_keys($info->getFilelist());
  25962.         $command = "cvs";
  25963.         if (isset($options['quiet'])) {
  25964.             $command .= ' -q';
  25965.         }
  25966.         if (isset($options['reallyquiet'])) {
  25967.             $command .= ' -Q';
  25968.         }
  25969.         $command .= ' tag';
  25970.         if (isset($options['slide'])) {
  25971.             $command .= ' -F';
  25972.         }
  25973.         if (isset($options['delete'])) {
  25974.             $command .= ' -d';
  25975.         }
  25976.         $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
  25977.         array_shift($params);
  25978.         if (count($params)) {
  25979.             // add in additional files to be tagged
  25980.             $files = array_merge($files, $params);
  25981.         }
  25982.         foreach ($files as $file) {
  25983.             $command .= ' ' . escapeshellarg($file);
  25984.         }
  25985.         if ($this->config->get('verbose') > 1) {
  25986.             $this->output .= "+ $command\n";
  25987.         }
  25988.         $this->output .= "+ $command\n";
  25989.         if (empty($options['dry-run'])) {
  25990.             $fp = popen($command, "r");
  25991.             while ($line = fgets($fp, 1024)) {
  25992.                 $this->output .= rtrim($line)."\n";
  25993.             }
  25994.             pclose($fp);
  25995.         }
  25996.         $this->ui->outputData($this->output, $_cmd);
  25997.         return true;
  25998.     }
  25999.  
  26000.     // }}}
  26001.     // {{{ doCvsDiff()
  26002.  
  26003.     function doCvsDiff($command, $options, $params)
  26004.     {
  26005.         $this->output = '';
  26006.         if (sizeof($params) < 1) {
  26007.             $help = $this->getHelp($command);
  26008.             return $this->raiseError("$command: missing parameter: $help[0]");
  26009.         }
  26010.         $obj = &$this->getPackageFile($this->config, $this->_debug);
  26011.         $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  26012.         if (PEAR::isError($info)) {
  26013.             return $this->raiseError($info);
  26014.         }
  26015.         $err = $warn = array();
  26016.         if (!$info->validate()) {
  26017.             foreach ($info->getValidationWarnings() as $error) {
  26018.                 if ($error['level'] == 'warning') {
  26019.                     $warn[] = $error['message'];
  26020.                 } else {
  26021.                     $err[] = $error['message'];
  26022.                 }
  26023.             }
  26024.         }
  26025.         if (!$this->_displayValidationResults($err, $warn, true)) {
  26026.             $this->ui->outputData($this->output, $command);
  26027.             return $this->raiseError('CVS diff failed');
  26028.         }
  26029.         $info1 = $info->getFilelist();
  26030.         $files = $info1;
  26031.         $cmd = "cvs";
  26032.         if (isset($options['quiet'])) {
  26033.             $cmd .= ' -q';
  26034.             unset($options['quiet']);
  26035.         }
  26036.         if (isset($options['reallyquiet'])) {
  26037.             $cmd .= ' -Q';
  26038.             unset($options['reallyquiet']);
  26039.         }
  26040.         if (isset($options['release'])) {
  26041.             $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
  26042.             $cvstag = "RELEASE_$cvsversion";
  26043.             $options['revision'] = $cvstag;
  26044.             unset($options['release']);
  26045.         }
  26046.         $execute = true;
  26047.         if (isset($options['dry-run'])) {
  26048.             $execute = false;
  26049.             unset($options['dry-run']);
  26050.         }
  26051.         $cmd .= ' diff';
  26052.         // the rest of the options are passed right on to "cvs diff"
  26053.         foreach ($options as $option => $optarg) {
  26054.             $arg = @$this->commands[$command]['options'][$option]['arg'];
  26055.             $short = @$this->commands[$command]['options'][$option]['shortopt'];
  26056.             $cmd .= $short ? " -$short" : " --$option";
  26057.             if ($arg && $optarg) {
  26058.                 $cmd .= ($short ? '' : '=') . escapeshellarg($optarg);
  26059.             }
  26060.         }
  26061.         foreach ($files as $file) {
  26062.             $cmd .= ' ' . escapeshellarg($file['name']);
  26063.         }
  26064.         if ($this->config->get('verbose') > 1) {
  26065.             $this->output .= "+ $cmd\n";
  26066.         }
  26067.         if ($execute) {
  26068.             $fp = popen($cmd, "r");
  26069.             while ($line = fgets($fp, 1024)) {
  26070.                 $this->output .= rtrim($line)."\n";
  26071.             }
  26072.             pclose($fp);
  26073.         }
  26074.         $this->ui->outputData($this->output, $command);
  26075.         return true;
  26076.     }
  26077.  
  26078.     // }}}
  26079.     // {{{ doPackageDependencies()
  26080.  
  26081.     function doPackageDependencies($command, $options, $params)
  26082.     {
  26083.         // $params[0] -> the PEAR package to list its information
  26084.         if (sizeof($params) != 1) {
  26085.             return $this->raiseError("bad parameter(s), try \"help $command\"");
  26086.         }
  26087.         $obj = &$this->getPackageFile($this->config, $this->_debug);
  26088.         $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  26089.         if (PEAR::isError($info)) {
  26090.             return $this->raiseError($info);
  26091.         }
  26092.         $deps = $info->getDeps();
  26093.         if (is_array($deps)) {
  26094.             if ($info->getPackagexmlVersion() == '1.0') {
  26095.                 $data = array(
  26096.                     'caption' => 'Dependencies for pear/' . $info->getPackage(),
  26097.                     'border' => true,
  26098.                     'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
  26099.                     );
  26100.  
  26101.                 foreach ($deps as $d) {
  26102.                     if (isset($d['optional'])) {
  26103.                         if ($d['optional'] == 'yes') {
  26104.                             $req = 'No';
  26105.                         } else {
  26106.                             $req = 'Yes';
  26107.                         }
  26108.                     } else {
  26109.                         $req = 'Yes';
  26110.                     }
  26111.                     if (isset($this->_deps_rel_trans[$d['rel']])) {
  26112.                         $rel = $this->_deps_rel_trans[$d['rel']];
  26113.                     } else {
  26114.                         $rel = $d['rel'];
  26115.                     }
  26116.  
  26117.                     if (isset($this->_deps_type_trans[$d['type']])) {
  26118.                         $type = ucfirst($this->_deps_type_trans[$d['type']]);
  26119.                     } else {
  26120.                         $type = $d['type'];
  26121.                     }
  26122.  
  26123.                     if (isset($d['name'])) {
  26124.                         $name = $d['name'];
  26125.                     } else {
  26126.                         $name = '';
  26127.                     }
  26128.  
  26129.                     if (isset($d['version'])) {
  26130.                         $version = $d['version'];
  26131.                     } else {
  26132.                         $version = '';
  26133.                     }
  26134.  
  26135.                     $data['data'][] = array($req, $type, $name, $rel, $version);
  26136.                 }
  26137.             } else { // package.xml 2.0 dependencies display
  26138.                 require_once 'PEAR/Dependency2.php';
  26139.                 $deps = $info->getDependencies();
  26140.                 $reg = &$this->config->getRegistry();
  26141.                 if (is_array($deps)) {
  26142.                     $d = new PEAR_Dependency2($this->config, array(), '');
  26143.                     $data = array(
  26144.                         'caption' => 'Dependencies for ' . $info->getPackage(),
  26145.                         'border' => true,
  26146.                         'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
  26147.                         );
  26148.                     foreach ($deps as $type => $subd) {
  26149.                         $req = ($type == 'required') ? 'Yes' : 'No';
  26150.                         if ($type == 'group') {
  26151.                             $group = $subd['attribs']['name'];
  26152.                         } else {
  26153.                             $group = '';
  26154.                         }
  26155.                         if (!isset($subd[0])) {
  26156.                             $subd = array($subd);
  26157.                         }
  26158.                         foreach ($subd as $groupa) {
  26159.                             foreach ($groupa as $deptype => $depinfo) {
  26160.                                 if ($deptype == 'attribs') {
  26161.                                     continue;
  26162.                                 }
  26163.                                 if ($deptype == 'pearinstaller') {
  26164.                                     $deptype = 'pear Installer';
  26165.                                 }
  26166.                                 if (!isset($depinfo[0])) {
  26167.                                     $depinfo = array($depinfo);
  26168.                                 }
  26169.                                 foreach ($depinfo as $inf) {
  26170.                                     $name = '';
  26171.                                     if (isset($inf['channel'])) {
  26172.                                         $alias = $reg->channelAlias($inf['channel']);
  26173.                                         if (!$alias) {
  26174.                                             $alias = '(channel?) ' .$inf['channel'];
  26175.                                         }
  26176.                                         $name = $alias . '/';
  26177.                                     }
  26178.                                     if (isset($inf['name'])) {
  26179.                                         $name .= $inf['name'];
  26180.                                     } elseif (isset($inf['pattern'])) {
  26181.                                         $name .= $inf['pattern'];
  26182.                                     } else {
  26183.                                         $name .= '';
  26184.                                     }
  26185.                                     if (isset($inf['uri'])) {
  26186.                                         $name .= ' [' . $inf['uri'] .  ']';
  26187.                                     }
  26188.                                     if (isset($inf['conflicts'])) {
  26189.                                         $ver = 'conflicts';
  26190.                                     } else {
  26191.                                         $ver = $d->_getExtraString($inf);
  26192.                                     }
  26193.                                     $data['data'][] = array($req, ucfirst($deptype), $name,
  26194.                                         $ver, $group);
  26195.                                 }
  26196.                             }
  26197.                         }
  26198.                     }
  26199.                 }
  26200.             }
  26201.  
  26202.             $this->ui->outputData($data, $command);
  26203.             return true;
  26204.         }
  26205.  
  26206.         // Fallback
  26207.         $this->ui->outputData("This package does not have any dependencies.", $command);
  26208.     }
  26209.  
  26210.     // }}}
  26211.     // {{{ doSign()
  26212.  
  26213.     function doSign($command, $options, $params)
  26214.     {
  26215.         require_once 'System.php';
  26216.         require_once 'Archive/Tar.php';
  26217.         // should move most of this code into PEAR_Packager
  26218.         // so it'll be easy to implement "pear package --sign"
  26219.         if (sizeof($params) != 1) {
  26220.             return $this->raiseError("bad parameter(s), try \"help $command\"");
  26221.         }
  26222.         if (!file_exists($params[0])) {
  26223.             return $this->raiseError("file does not exist: $params[0]");
  26224.         }
  26225.         $obj = $this->getPackageFile($this->config, $this->_debug);
  26226.         $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
  26227.         if (PEAR::isError($info)) {
  26228.             return $this->raiseError($info);
  26229.         }
  26230.         $tar = new Archive_Tar($params[0]);
  26231.         $tmpdir = System::mktemp('-d pearsign');
  26232.         if (!$tar->extractList('package2.xml package.sig', $tmpdir)) {
  26233.             if (!$tar->extractList('package.xml package.sig', $tmpdir)) {
  26234.                 return $this->raiseError("failed to extract tar file");
  26235.             }
  26236.         }
  26237.         if (file_exists("$tmpdir/package.sig")) {
  26238.             return $this->raiseError("package already signed");
  26239.         }
  26240.         $packagexml = 'package.xml';
  26241.         if (file_exists("$tmpdir/package2.xml")) {
  26242.             $packagexml = 'package2.xml';
  26243.         }
  26244.         @unlink("$tmpdir/package.sig");
  26245.         $input = $this->ui->userDialog($command,
  26246.                                        array('GnuPG Passphrase'),
  26247.                                        array('password'));
  26248.         $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml 2>/dev/null", "w");
  26249.         if (!$gpg) {
  26250.             return $this->raiseError("gpg command failed");
  26251.         }
  26252.         fwrite($gpg, "$input[0]\n");
  26253.         if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
  26254.             return $this->raiseError("gpg sign failed");
  26255.         }
  26256.         $tar->addModify("$tmpdir/package.sig", '', $tmpdir);
  26257.         return true;
  26258.     }
  26259.  
  26260.     // }}}
  26261.  
  26262.     /**
  26263.      * For unit testing purposes
  26264.      */
  26265.     function &getInstaller(&$ui)
  26266.     {
  26267.         if (!class_exists('PEAR_Installer')) {
  26268.             require_once 'PEAR/Installer.php';
  26269.         }
  26270.         $a = &new PEAR_Installer($ui);
  26271.         return $a;
  26272.     }
  26273.     
  26274.     /**
  26275.      * For unit testing purposes
  26276.      */
  26277.     function &getCommandPackaging(&$ui, &$config)
  26278.     {
  26279.         if (!class_exists('PEAR_Command_Packaging')) {
  26280.             @include_once 'PEAR/Command/Packaging.php';
  26281.         }
  26282.         
  26283.         if (class_exists('PEAR_Command_Packaging')) {
  26284.             $a = &new PEAR_Command_Packaging($ui, $config);
  26285.         } else {
  26286.             $a = null;
  26287.         }
  26288.         return $a;
  26289.     }
  26290.  
  26291.     // {{{ doMakeRPM()
  26292.  
  26293.     function doMakeRPM($command, $options, $params)
  26294.     {
  26295.         require_once 'System.php';
  26296.         require_once 'Archive/Tar.php';
  26297.  
  26298.         // Check to see if PEAR_Command_Packaging is installed, and
  26299.         // transparently switch to use the "make-rpm-spec" command from it
  26300.         // instead, if it does. Otherwise, continue to use the old version
  26301.         // of "makerpm" supplied with this package (PEAR).
  26302.         $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config);
  26303.         if ($packaging_cmd !== null) {
  26304.             $this->ui->outputData('PEAR_Command_Packaging is installed; using '.
  26305.                 'newer "make-rpm-spec" command instead');
  26306.             return $packaging_cmd->run('make-rpm-spec', $options, $params);
  26307.         } else {
  26308.             $this->ui->outputData('WARNING: "pear makerpm" is now deprecated; an '.
  26309.               'improved version is available via "pear make-rpm-spec", which '.
  26310.               'is available by installing PEAR_Command_Packaging');
  26311.         }
  26312.         
  26313.         if (sizeof($params) != 1) {
  26314.             return $this->raiseError("bad parameter(s), try \"help $command\"");
  26315.         }
  26316.         if (!file_exists($params[0])) {
  26317.             return $this->raiseError("file does not exist: $params[0]");
  26318.         }
  26319.         $reg = &$this->config->getRegistry();
  26320.         $pkg = &$this->getPackageFile($this->config, $this->_debug);
  26321.         $pf = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  26322.         if (PEAR::isError($pf)) {
  26323.             $u = $pf->getUserinfo();
  26324.             if (is_array($u)) {
  26325.                 foreach ($u as $err) {
  26326.                     if (is_array($err)) {
  26327.                         $err = $err['message'];
  26328.                     }
  26329.                     $this->ui->outputData($err);
  26330.                 }
  26331.             }
  26332.             return $this->raiseError("$params[0] is not a valid package");
  26333.         }
  26334.         $tmpdir = System::mktemp(array('-d', 'pear2rpm'));
  26335.         $instroot = System::mktemp(array('-d', 'pear2rpm'));
  26336.         $tmp = $this->config->get('verbose');
  26337.         $this->config->set('verbose', 0);
  26338.         $installer = $this->getInstaller($this->ui);
  26339.         require_once 'PEAR/Downloader/Package.php';
  26340.         $pack = new PEAR_Downloader_Package($installer);
  26341.         $pack->setPackageFile($pf);
  26342.         $params[0] = &$pack;
  26343.         $installer->setOptions(array('installroot' => $instroot,
  26344.                                           'nodeps' => true, 'soft' => true));
  26345.         $installer->setDownloadedPackages($params);
  26346.         $info = $installer->install($params[0],
  26347.                                     array('installroot' => $instroot,
  26348.                                           'nodeps' => true, 'soft' => true));
  26349.         $pkgdir = $pf->getPackage() . '-' . $pf->getVersion();
  26350.         $info['rpm_xml_dir'] = '/var/lib/pear';
  26351.         $this->config->set('verbose', $tmp);
  26352.         if (isset($options['spec-template'])) {
  26353.             $spec_template = $options['spec-template'];
  26354.         } else {
  26355.             $spec_template = '@DATA-DIR@/PEAR/template.spec';
  26356.         }
  26357.         $info['possible_channel'] = '';
  26358.         $info['extra_config'] = '';
  26359.         if (isset($options['rpm-pkgname'])) {
  26360.             $rpm_pkgname_format = $options['rpm-pkgname'];
  26361.         } else {
  26362.             if ($pf->getChannel() == 'pear.php.net' || $pf->getChannel() == 'pecl.php.net') {
  26363.                 $alias = 'PEAR';
  26364.             } else {
  26365.                 $chan = &$reg->getChannel($pf->getChannel());
  26366.                 if (PEAR::isError($chan)) {
  26367.                     return $this->raiseError($chan);
  26368.                 }
  26369.                 $alias = $chan->getAlias();
  26370.                 $alias = strtoupper($alias);
  26371.                 $info['possible_channel'] = $pf->getChannel() . '/';
  26372.             }
  26373.             $rpm_pkgname_format = $alias . '::%s';
  26374.         }
  26375.  
  26376.         $info['extra_headers'] = '';
  26377.         $info['doc_files'] = '';
  26378.         $info['files'] = '';
  26379.         $info['package2xml'] = '';
  26380.         $info['rpm_package'] = sprintf($rpm_pkgname_format, $pf->getPackage());
  26381.         $srcfiles = 0;
  26382.         foreach ($info['filelist'] as $name => $attr) {
  26383.             if (!isset($attr['role'])) {
  26384.                 continue;
  26385.             }
  26386.             $name = preg_replace('![/:\\\\]!', '/', $name);
  26387.             if ($attr['role'] == 'doc') {
  26388.                 $info['doc_files'] .= " $name";
  26389.             // Map role to the rpm vars
  26390.             } else {
  26391.                 $c_prefix = '%{_libdir}/php/pear';
  26392.                 switch ($attr['role']) {
  26393.                     case 'php':
  26394.                         $prefix = $c_prefix;
  26395.                     break;
  26396.                     case 'ext':
  26397.                         $prefix = '%{_libdir}/php';
  26398.                     break; // XXX good place?
  26399.                     case 'src':
  26400.                         $srcfiles++;
  26401.                         $prefix = '%{_includedir}/php';
  26402.                     break; // XXX good place?
  26403.                     case 'test':
  26404.                         $prefix = "$c_prefix/tests/" . $pf->getPackage();
  26405.                     break;
  26406.                     case 'data':
  26407.                         $prefix = "$c_prefix/data/" . $pf->getPackage();
  26408.                     break;
  26409.                     case 'script':
  26410.                         $prefix = '%{_bindir}';
  26411.                     break;
  26412.                     default: // non-standard roles
  26413.                         $prefix = "$c_prefix/$attr[role]/" . $pf->getPackage();
  26414.                         $info['extra_config'] .=
  26415.                         "\n        -d {$attr[role]}_dir=$c_prefix/{$attr[role]} \\";
  26416.                         $this->ui->outputData('WARNING: role "' . $attr['role'] . '" used, ' .
  26417.                             'and will be installed in "' . $c_prefix . '/' . $attr['role'] .
  26418.                             '/' . $pf->getPackage() .
  26419.                             ' - hand-edit the final .spec if this is wrong', $command);
  26420.                     break;
  26421.                 }
  26422.                 $name = str_replace('\\', '/', $name);
  26423.                 $info['files'] .= "$prefix/$name\n";
  26424.             }
  26425.         }
  26426.         if ($srcfiles > 0) {
  26427.             require_once 'OS/Guess.php';
  26428.             $os = new OS_Guess;
  26429.             $arch = $os->getCpu();
  26430.         } else {
  26431.             $arch = 'noarch';
  26432.         }
  26433.         $cfg = array('master_server', 'php_dir', 'ext_dir', 'doc_dir',
  26434.                      'bin_dir', 'data_dir', 'test_dir');
  26435.         foreach ($cfg as $k) {
  26436.             if ($k == 'master_server') {
  26437.                 $chan = $reg->getChannel($pf->getChannel());
  26438.                 if (PEAR::isError($chan)) {
  26439.                     return $this->raiseError($chan);
  26440.                 }
  26441.                 $info[$k] = $chan->getServer();
  26442.                 continue;
  26443.             }
  26444.             $info[$k] = $this->config->get($k);
  26445.         }
  26446.         $info['arch'] = $arch;
  26447.         $fp = @fopen($spec_template, "r");
  26448.         if (!$fp) {
  26449.             return $this->raiseError("could not open RPM spec file template $spec_template: $php_errormsg");
  26450.         }
  26451.         $info['package'] = $pf->getPackage();
  26452.         $info['version'] = $pf->getVersion();
  26453.         $info['release_license'] = $pf->getLicense();
  26454.         if ($pf->getDeps()) {
  26455.             if ($pf->getPackagexmlVersion() == '1.0') {
  26456.                 $requires = $conflicts = array();
  26457.                 foreach ($pf->getDeps() as $dep) {
  26458.                     if (isset($dep['optional']) && $dep['optional'] == 'yes') {
  26459.                         continue;
  26460.                     }
  26461.                     if ($dep['type'] != 'pkg') {
  26462.                         continue;
  26463.                     }
  26464.                     if (isset($dep['channel']) && $dep['channel'] != 'pear.php.net' &&
  26465.                           $dep['channel'] != 'pecl.php.net') {
  26466.                         $chan = &$reg->getChannel($dep['channel']);
  26467.                         if (PEAR::isError($chan)) {
  26468.                             return $this->raiseError($chan);
  26469.                         }
  26470.                         $package = strtoupper($chan->getAlias()) . '::' . $dep['name'];
  26471.                     } else {
  26472.                         $package = 'PEAR::' . $dep['name'];
  26473.                     }
  26474.                     $trans = array(
  26475.                         '>' => '>',
  26476.                         '<' => '<',
  26477.                         '>=' => '>=',
  26478.                         '<=' => '<=',
  26479.                         '=' => '=',
  26480.                         'gt' => '>',
  26481.                         'lt' => '<',
  26482.                         'ge' => '>=',
  26483.                         'le' => '<=',
  26484.                         'eq' => '=',
  26485.                     );
  26486.                     if ($dep['rel'] == 'has') {
  26487.                         $requires[] = $package;
  26488.                     } elseif ($dep['rel'] == 'not') {
  26489.                         $conflicts[] = $package;
  26490.                     } elseif ($dep['rel'] == 'ne') {
  26491.                         $conflicts[] = $package . ' = ' . $dep['version'];
  26492.                     } elseif (isset($trans[$dep['rel']])) {
  26493.                         $requires[] = $package . ' ' . $trans[$dep['rel']] . ' ' . $dep['version'];
  26494.                     }
  26495.                 }
  26496.                 if (count($requires)) {
  26497.                     $info['extra_headers'] .= 'Requires: ' . implode(', ', $requires) . "\n";
  26498.                 }
  26499.                 if (count($conflicts)) {
  26500.                     $info['extra_headers'] .= 'Conflicts: ' . implode(', ', $conflicts) . "\n";
  26501.                 }
  26502.             } else {
  26503.                 $info['package2xml'] = '2'; // tell the spec to use package2.xml
  26504.                 $requires = $conflicts = array();
  26505.                 $deps = $pf->getDeps(true);
  26506.                 if (isset($deps['required']['package'])) {
  26507.                     if (!isset($deps['required']['package'][0])) {
  26508.                         $deps['required']['package'] = array($deps['required']['package']);
  26509.                     }
  26510.                     foreach ($deps['required']['package'] as $dep) {
  26511.                         if ($dep['channel'] != 'pear.php.net' &&  $dep['channel'] != 'pecl.php.net') {
  26512.                             $chan = &$reg->getChannel($dep['channel']);
  26513.                             if (PEAR::isError($chan)) {
  26514.                                 return $this->raiseError($chan);
  26515.                             }
  26516.                             $package = strtoupper($chan->getAlias()) . '::' . $dep['name'];
  26517.                         } else {
  26518.                             $package = 'PEAR::' . $dep['name'];
  26519.                         }
  26520.                         if (isset($dep['conflicts']) && (isset($dep['min']) ||
  26521.                               isset($dep['max']))) {
  26522.                             $deprange = array();
  26523.                             if (isset($dep['min'])) {
  26524.                                 $deprange[] = array($dep['min'],'>=');
  26525.                             }
  26526.                             if (isset($dep['max'])) {
  26527.                                 $deprange[] = array($dep['max'], '<=');
  26528.                             }
  26529.                             if (isset($dep['exclude'])) {
  26530.                                 if (!is_array($dep['exclude']) ||
  26531.                                       !isset($dep['exclude'][0])) {
  26532.                                     $dep['exclude'] = array($dep['exclude']);
  26533.                                 }
  26534.                                 if (count($deprange)) {
  26535.                                     $excl = $dep['exclude'];
  26536.                                     // change >= to > if excluding the min version
  26537.                                     // change <= to < if excluding the max version
  26538.                                     for($i = 0; $i < count($excl); $i++) {
  26539.                                         if (isset($deprange[0]) &&
  26540.                                               $excl[$i] == $deprange[0][0]) {
  26541.                                             $deprange[0][1] = '<';
  26542.                                             unset($dep['exclude'][$i]);
  26543.                                         }
  26544.                                         if (isset($deprange[1]) &&
  26545.                                               $excl[$i] == $deprange[1][0]) {
  26546.                                             $deprange[1][1] = '>';
  26547.                                             unset($dep['exclude'][$i]);
  26548.                                         }
  26549.                                     }
  26550.                                 }
  26551.                                 if (count($dep['exclude'])) {
  26552.                                     $dep['exclude'] = array_values($dep['exclude']);
  26553.                                     $newdeprange = array();
  26554.                                     // remove excludes that are outside the existing range
  26555.                                     for ($i = 0; $i < count($dep['exclude']); $i++) {
  26556.                                         if ($dep['exclude'][$i] < $dep['min'] ||
  26557.                                               $dep['exclude'][$i] > $dep['max']) {
  26558.                                             unset($dep['exclude'][$i]);
  26559.                                         }
  26560.                                     }
  26561.                                     $dep['exclude'] = array_values($dep['exclude']);
  26562.                                     usort($dep['exclude'], 'version_compare');
  26563.                                     // take the remaining excludes and
  26564.                                     // split the dependency into sub-ranges
  26565.                                     $lastmin = $deprange[0];
  26566.                                     for ($i = 0; $i < count($dep['exclude']) - 1; $i++) {
  26567.                                         $newdeprange[] = '(' .
  26568.                                             $package . " {$lastmin[1]} {$lastmin[0]} and " .
  26569.                                             $package . ' < ' . $dep['exclude'][$i] . ')';
  26570.                                         $lastmin = array($dep['exclude'][$i], '>');
  26571.                                     }
  26572.                                     if (isset($dep['max'])) {
  26573.                                         $newdeprange[] = '(' . $package .
  26574.                                             " {$lastmin[1]} {$lastmin[0]} and " .
  26575.                                             $package . ' < ' . $dep['max'] . ')';
  26576.                                     }
  26577.                                     $conflicts[] = implode(' or ', $deprange);
  26578.                                 } else {
  26579.                                     $conflicts[] = $package .
  26580.                                         " {$deprange[0][1]} {$deprange[0][0]}" .
  26581.                                         (isset($deprange[1]) ? 
  26582.                                         " and $package {$deprange[1][1]} {$deprange[1][0]}"
  26583.                                         : '');
  26584.                                 }
  26585.                             }
  26586.                             continue;
  26587.                         }
  26588.                         if (!isset($dep['min']) && !isset($dep['max']) &&
  26589.                               !isset($dep['exclude'])) {
  26590.                             if (isset($dep['conflicts'])) {
  26591.                                 $conflicts[] = $package;
  26592.                             } else {
  26593.                                 $requires[] = $package;
  26594.                             }
  26595.                         } else {
  26596.                             if (isset($dep['min'])) {
  26597.                                 $requires[] = $package . ' >= ' . $dep['min'];
  26598.                             }
  26599.                             if (isset($dep['max'])) {
  26600.                                 $requires[] = $package . ' <= ' . $dep['max'];
  26601.                             }
  26602.                             if (isset($dep['exclude'])) {
  26603.                                 $ex = $dep['exclude'];
  26604.                                 if (!is_array($ex)) {
  26605.                                     $ex = array($ex);
  26606.                                 }
  26607.                                 foreach ($ex as $ver) {
  26608.                                     $conflicts[] = $package . ' = ' . $ver;
  26609.                                 }
  26610.                             }
  26611.                         }
  26612.                     }
  26613.                     require_once 'Archive/Tar.php';
  26614.                     $tar = new Archive_Tar($pf->getArchiveFile());
  26615.                     $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  26616.                     $a = $tar->extractInString('package2.xml');
  26617.                     $tar->popErrorHandling();
  26618.                     if ($a === null || PEAR::isError($a)) {
  26619.                         $info['package2xml'] = '';
  26620.                         // this doesn't have a package.xml version 1.0
  26621.                         $requires[] = 'PEAR::PEAR >= ' .
  26622.                             $deps['required']['pearinstaller']['min'];
  26623.                     }
  26624.                     if (count($requires)) {
  26625.                         $info['extra_headers'] .= 'Requires: ' . implode(', ', $requires) . "\n";
  26626.                     }
  26627.                     if (count($conflicts)) {
  26628.                         $info['extra_headers'] .= 'Conflicts: ' . implode(', ', $conflicts) . "\n";
  26629.                     }
  26630.                 }
  26631.             }
  26632.         }
  26633.  
  26634.         // remove the trailing newline
  26635.         $info['extra_headers'] = trim($info['extra_headers']);
  26636.         if (function_exists('file_get_contents')) {
  26637.             fclose($fp);
  26638.             $spec_contents = preg_replace('/@([a-z0-9_-]+)@/e', '$info["\1"]',
  26639.                 file_get_contents($spec_template));
  26640.         } else {
  26641.             $spec_contents = preg_replace('/@([a-z0-9_-]+)@/e', '$info["\1"]',
  26642.                 fread($fp, filesize($spec_template)));
  26643.             fclose($fp);
  26644.         }
  26645.         $spec_file = "$info[rpm_package]-$info[version].spec";
  26646.         $wp = fopen($spec_file, "wb");
  26647.         if (!$wp) {
  26648.             return $this->raiseError("could not write RPM spec file $spec_file: $php_errormsg");
  26649.         }
  26650.         fwrite($wp, $spec_contents);
  26651.         fclose($wp);
  26652.         $this->ui->outputData("Wrote RPM spec file $spec_file", $command);
  26653.  
  26654.         return true;
  26655.     }
  26656.  
  26657.     function doConvert($command, $options, $params)
  26658.     {
  26659.         $packagexml = isset($params[0]) ? $params[0] : 'package.xml';
  26660.         $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
  26661.             DIRECTORY_SEPARATOR . 'package2.xml';
  26662.         $pkg = &$this->getPackageFile($this->config, $this->_debug);
  26663.         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26664.         $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
  26665.         PEAR::staticPopErrorHandling();
  26666.         if (!PEAR::isError($pf)) {
  26667.             if (is_a($pf, 'PEAR_PackageFile_v2')) {
  26668.                 $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
  26669.                 return true;
  26670.             }
  26671.             $gen = &$pf->getDefaultGenerator();
  26672.             $newpf = &$gen->toV2();
  26673.             $newpf->setPackagefile($newpackagexml);
  26674.             $gen = &$newpf->getDefaultGenerator();
  26675.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  26676.             $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
  26677.             $saved = $gen->toPackageFile(dirname($newpackagexml), $state,
  26678.                 basename($newpackagexml));
  26679.             PEAR::staticPopErrorHandling();
  26680.             if (PEAR::isError($saved)) {
  26681.                 if (is_array($saved->getUserInfo())) {
  26682.                     foreach ($saved->getUserInfo() as $warning) {
  26683.                         $this->ui->outputData($warning['message']);
  26684.                     }
  26685.                 }
  26686.                 $this->ui->outputData($saved->getMessage());
  26687.                 return true;
  26688.             }
  26689.             $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');
  26690.             return true;
  26691.         } else {
  26692.             if (is_array($pf->getUserInfo())) {
  26693.                 foreach ($pf->getUserInfo() as $warning) {
  26694.                     $this->ui->outputData($warning['message']);
  26695.                 }
  26696.             }
  26697.             return $this->raiseError($pf);
  26698.         }
  26699.     }
  26700.  
  26701.     // }}}
  26702. }
  26703.  
  26704. ?>
  26705. PEAR-1.4.11/PEAR/Command/Pickle.xml100644   1750   1750        2714 10470570063  11613 <commands version="1.0">
  26706.  <pickle>
  26707.   <summary>Build PECL Package</summary>
  26708.   <function>doPackage</function>
  26709.   <shortcut>pi</shortcut>
  26710.   <options>
  26711.    <nocompress>
  26712.     <shortopt>Z</shortopt>
  26713.     <doc>Do not gzip the package file</doc>
  26714.    </nocompress>
  26715.    <showname>
  26716.     <shortopt>n</shortopt>
  26717.     <doc>Print the name of the packaged file.</doc>
  26718.    </showname>
  26719.   </options>
  26720.   <doc>[descfile] [descfile2]
  26721. Creates a PECL package from its description file (usually called
  26722. package.xml).  If a second packagefile is passed in, then
  26723. the packager will check to make sure that one is a package.xml
  26724. version 1.0, and the other is a package.xml version 2.0.  The
  26725. package.xml version 1.0 will be saved as "package.xml" in the archive,
  26726. and the other as "package2.xml" in the archive"
  26727.  
  26728. If no second file is passed in, and [descfile] is a package.xml 2.0,
  26729. an automatic conversion will be made to a package.xml 1.0.  Note that
  26730. only simple package.xml 2.0 will be converted.  package.xml 2.0 with:
  26731.  
  26732.  - dependency types other than required/optional PECL package/ext/php/pearinstaller
  26733.  - more than one extsrcrelease
  26734.  - extbinrelease, phprelease, or bundle release type
  26735.  - dependency groups
  26736.  - ignore tags in release filelist
  26737.  - tasks other than replace
  26738.  - custom roles
  26739.  
  26740. will cause pickle to fail, and output an error message.  If your package2.xml
  26741. uses any of these features, you are best off using PEAR_PackageFileManager to
  26742. generate both package.xml.</doc>
  26743.  </pickle>
  26744. </commands>PEAR-1.4.11/PEAR/Command/Pickle.php100644   1750   1750       37265 10470570063  11633 <?php
  26745. /**
  26746.  * PEAR_Command_Pickle (pickle command)
  26747.  *
  26748.  * PHP versions 4 and 5
  26749.  *
  26750.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  26751.  * that is available through the world-wide-web at the following URI:
  26752.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  26753.  * the PHP License and are unable to obtain it through the web, please
  26754.  * send a note to license@php.net so we can mail you a copy immediately.
  26755.  *
  26756.  * @category   pear
  26757.  * @package    PEAR
  26758.  * @author     Greg Beaver <cellog@php.net>
  26759.  * @copyright  2005-2006 The PHP Group
  26760.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  26761.  * @version    CVS: $Id: Pickle.php,v 1.5.2.1 2006/05/10 03:25:15 cellog Exp $
  26762.  * @link       http://pear.php.net/package/PEAR
  26763.  * @since      File available since Release 1.4.1
  26764.  */
  26765.  
  26766. /**
  26767.  * base class
  26768.  */
  26769. require_once 'PEAR/Command/Common.php';
  26770.  
  26771. /**
  26772.  * PEAR commands for login/logout
  26773.  *
  26774.  * @category   pear
  26775.  * @package    PEAR
  26776.  * @author     Greg Beaver <cellog@php.net>
  26777.  * @copyright  2005-2006 The PHP Group
  26778.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  26779.  * @version    Release: 1.4.11
  26780.  * @link       http://pear.php.net/package/PEAR
  26781.  * @since      Class available since Release 1.4.1
  26782.  */
  26783.  
  26784. class PEAR_Command_Pickle extends PEAR_Command_Common
  26785. {
  26786.     var $commands = array(
  26787.         'pickle' => array(
  26788.             'summary' => 'Build PECL Package',
  26789.             'function' => 'doPackage',
  26790.             'shortcut' => 'pi',
  26791.             'options' => array(
  26792.                 'nocompress' => array(
  26793.                     'shortopt' => 'Z',
  26794.                     'doc' => 'Do not gzip the package file'
  26795.                     ),
  26796.                 'showname' => array(
  26797.                     'shortopt' => 'n',
  26798.                     'doc' => 'Print the name of the packaged file.',
  26799.                     ),
  26800.                 ),
  26801.             'doc' => '[descfile]
  26802. Creates a PECL package from its package2.xml file.
  26803.  
  26804. An automatic conversion will be made to a package.xml 1.0 and written out to
  26805. disk in the current directory as "package.xml".  Note that
  26806. only simple package.xml 2.0 will be converted.  package.xml 2.0 with:
  26807.  
  26808.  - dependency types other than required/optional PECL package/ext/php/pearinstaller
  26809.  - more than one extsrcrelease
  26810.  - extbinrelease, phprelease, or bundle release type
  26811.  - dependency groups
  26812.  - ignore tags in release filelist
  26813.  - tasks other than replace
  26814.  - custom roles
  26815.  
  26816. will cause pickle to fail, and output an error message.  If your package2.xml
  26817. uses any of these features, you are best off using PEAR_PackageFileManager to
  26818. generate both package.xml.
  26819. '
  26820.             ),
  26821.         );
  26822.  
  26823.     /**
  26824.      * PEAR_Command_Package constructor.
  26825.      *
  26826.      * @access public
  26827.      */
  26828.     function PEAR_Command_Pickle(&$ui, &$config)
  26829.     {
  26830.         parent::PEAR_Command_Common($ui, $config);
  26831.     }
  26832.  
  26833.  
  26834.     /**
  26835.      * For unit-testing ease
  26836.      *
  26837.      * @return PEAR_Packager
  26838.      */
  26839.     function &getPackager()
  26840.     {
  26841.         if (!class_exists('PEAR_Packager')) {
  26842.             require_once 'PEAR/Packager.php';
  26843.         }
  26844.         $a = &new PEAR_Packager;
  26845.         return $a;
  26846.     }
  26847.  
  26848.     /**
  26849.      * For unit-testing ease
  26850.      *
  26851.      * @param PEAR_Config $config
  26852.      * @param bool $debug
  26853.      * @param string|null $tmpdir
  26854.      * @return PEAR_PackageFile
  26855.      */
  26856.     function &getPackageFile($config, $debug = false, $tmpdir = null)
  26857.     {
  26858.         if (!class_exists('PEAR_Common')) {
  26859.             require_once 'PEAR/Common.php';
  26860.         }
  26861.         if (!class_exists('PEAR/PackageFile.php')) {
  26862.             require_once 'PEAR/PackageFile.php';
  26863.         }
  26864.         $a = &new PEAR_PackageFile($config, $debug, $tmpdir);
  26865.         $common = new PEAR_Common;
  26866.         $common->ui = $this->ui;
  26867.         $a->setLogger($common);
  26868.         return $a;
  26869.     }
  26870.  
  26871.     function doPackage($command, $options, $params)
  26872.     {
  26873.         $this->output = '';
  26874.         $pkginfofile = isset($params[0]) ? $params[0] : 'package2.xml';
  26875.         $packager = &$this->getPackager();
  26876.         if (PEAR::isError($err = $this->_convertPackage($pkginfofile))) {
  26877.             return $err;
  26878.         }
  26879.         $compress = empty($options['nocompress']) ? true : false;
  26880.         $result = $packager->package($pkginfofile, $compress, 'package.xml');
  26881.         if (PEAR::isError($result)) {
  26882.             return $this->raiseError($result);
  26883.         }
  26884.         // Don't want output, only the package file name just created
  26885.         if (isset($options['showname'])) {
  26886.             $this->ui->outputData($result, $command);
  26887.         }
  26888.         return true;
  26889.     }
  26890.  
  26891.     function _convertPackage($packagexml)
  26892.     {
  26893.         $pkg = &$this->getPackageFile($this->config);
  26894.         $pf2 = &$pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
  26895.         if (!is_a($pf2, 'PEAR_PackageFile_v2')) {
  26896.             return $this->raiseError('Cannot process "' .
  26897.                 $packagexml . '", is not a package.xml 2.0');
  26898.         }
  26899.         require_once 'PEAR/PackageFile/v1.php';
  26900.         $pf = new PEAR_PackageFile_v1;
  26901.         $pf->setConfig($this->config);
  26902.         if ($pf2->getPackageType() != 'extsrc') {
  26903.             return $this->raiseError('Cannot safely convert "' . $packagexml .
  26904.             '", is not an extension source package.  Using a PEAR_PackageFileManager-based ' .
  26905.             'script is an option');
  26906.         }
  26907.         if (is_array($pf2->getUsesRole())) {
  26908.             return $this->raiseError('Cannot safely convert "' . $packagexml .
  26909.             '", contains custom roles.  Using a PEAR_PackageFileManager-based script or ' .
  26910.             'the convert command is an option');
  26911.         }
  26912.         if (is_array($pf2->getUsesTask())) {
  26913.             return $this->raiseError('Cannot safely convert "' . $packagexml .
  26914.             '", contains custom tasks.  Using a PEAR_PackageFileManager-based script or ' .
  26915.             'the convert command is an option');
  26916.         }
  26917.         $deps = $pf2->getDependencies();
  26918.         if (isset($deps['group'])) {
  26919.             return $this->raiseError('Cannot safely convert "' . $packagexml .
  26920.             '", contains dependency groups.  Using a PEAR_PackageFileManager-based script ' .
  26921.             'or the convert command is an option');
  26922.         }
  26923.         if (isset($deps['required']['subpackage']) ||
  26924.               isset($deps['optional']['subpackage'])) {
  26925.             return $this->raiseError('Cannot safely convert "' . $packagexml .
  26926.             '", contains subpackage dependencies.  Using a PEAR_PackageFileManager-based  '.
  26927.             'script is an option');
  26928.         }
  26929.         if (isset($deps['required']['os'])) {
  26930.             return $this->raiseError('Cannot safely convert "' . $packagexml .
  26931.             '", contains os dependencies.  Using a PEAR_PackageFileManager-based  '.
  26932.             'script is an option');
  26933.         }
  26934.         if (isset($deps['required']['arch'])) {
  26935.             return $this->raiseError('Cannot safely convert "' . $packagexml .
  26936.             '", contains arch dependencies.  Using a PEAR_PackageFileManager-based  '.
  26937.             'script is an option');
  26938.         }
  26939.         $pf->setPackage($pf2->getPackage());
  26940.         $pf->setSummary($pf2->getSummary());
  26941.         $pf->setDescription($pf2->getDescription());
  26942.         foreach ($pf2->getMaintainers() as $maintainer) {
  26943.             $pf->addMaintainer($maintainer['role'], $maintainer['handle'],
  26944.                 $maintainer['name'], $maintainer['email']);
  26945.         }
  26946.         $pf->setVersion($pf2->getVersion());
  26947.         $pf->setDate($pf2->getDate());
  26948.         $pf->setLicense($pf2->getLicense());
  26949.         $pf->setState($pf2->getState());
  26950.         $pf->setNotes($pf2->getNotes());
  26951.         $pf->addPhpDep($deps['required']['php']['min'], 'ge');
  26952.         if (isset($deps['required']['php']['max'])) {
  26953.             $pf->addPhpDep($deps['required']['php']['max'], 'le');
  26954.         }
  26955.         if (isset($deps['required']['package'])) {
  26956.             if (!isset($deps['required']['package'][0])) {
  26957.                 $deps['required']['package'] = array($deps['required']['package']);
  26958.             }
  26959.             foreach ($deps['required']['package'] as $dep) {
  26960.                 if (!isset($dep['channel'])) {
  26961.                     return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  26962.                     ' contains uri-based dependency on a package.  Using a ' .
  26963.                     'PEAR_PackageFileManager-based script is an option');
  26964.                 }
  26965.                 if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') {
  26966.                     return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  26967.                     ' contains dependency on a non-standard channel package.  Using a ' .
  26968.                     'PEAR_PackageFileManager-based script is an option');
  26969.                 }
  26970.                 if (isset($dep['conflicts'])) {
  26971.                     return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  26972.                     ' contains conflicts dependency.  Using a ' .
  26973.                     'PEAR_PackageFileManager-based script is an option');
  26974.                 }
  26975.                 if (isset($dep['exclude'])) {
  26976.                     $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
  26977.                 }
  26978.                 if (isset($dep['min'])) {
  26979.                     $pf->addPackageDep($dep['name'], $dep['min'], 'ge');
  26980.                 }
  26981.                 if (isset($dep['max'])) {
  26982.                     $pf->addPackageDep($dep['name'], $dep['max'], 'le');
  26983.                 }
  26984.             }
  26985.         }
  26986.         if (isset($deps['required']['extension'])) {
  26987.             if (!isset($deps['required']['extension'][0])) {
  26988.                 $deps['required']['extension'] = array($deps['required']['extension']);
  26989.             }
  26990.             foreach ($deps['required']['extension'] as $dep) {
  26991.                 if (isset($dep['conflicts'])) {
  26992.                     return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  26993.                     ' contains conflicts dependency.  Using a ' .
  26994.                     'PEAR_PackageFileManager-based script is an option');
  26995.                 }
  26996.                 if (isset($dep['exclude'])) {
  26997.                     $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
  26998.                 }
  26999.                 if (isset($dep['min'])) {
  27000.                     $pf->addExtensionDep($dep['name'], $dep['min'], 'ge');
  27001.                 }
  27002.                 if (isset($dep['max'])) {
  27003.                     $pf->addExtensionDep($dep['name'], $dep['max'], 'le');
  27004.                 }
  27005.             }
  27006.         }
  27007.         if (isset($deps['optional']['package'])) {
  27008.             if (!isset($deps['optional']['package'][0])) {
  27009.                 $deps['optional']['package'] = array($deps['optional']['package']);
  27010.             }
  27011.             foreach ($deps['optional']['package'] as $dep) {
  27012.                 if (!isset($dep['channel'])) {
  27013.                     return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  27014.                     ' contains uri-based dependency on a package.  Using a ' .
  27015.                     'PEAR_PackageFileManager-based script is an option');
  27016.                 }
  27017.                 if ($dep['channel'] != 'pear.php.net' && $dep['channel'] != 'pecl.php.net') {
  27018.                     return $this->raiseError('Cannot safely convert "' . $packagexml . '"' .
  27019.                     ' contains dependency on a non-standard channel package.  Using a ' .
  27020.                     'PEAR_PackageFileManager-based script is an option');
  27021.                 }
  27022.                 if (isset($dep['exclude'])) {
  27023.                     $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
  27024.                 }
  27025.                 if (isset($dep['min'])) {
  27026.                     $pf->addPackageDep($dep['name'], $dep['min'], 'ge', 'yes');
  27027.                 }
  27028.                 if (isset($dep['max'])) {
  27029.                     $pf->addPackageDep($dep['name'], $dep['max'], 'le', 'yes');
  27030.                 }
  27031.             }
  27032.         }
  27033.         if (isset($deps['optional']['extension'])) {
  27034.             if (!isset($deps['optional']['extension'][0])) {
  27035.                 $deps['optional']['extension'] = array($deps['optional']['extension']);
  27036.             }
  27037.             foreach ($deps['optional']['extension'] as $dep) {
  27038.                 if (isset($dep['exclude'])) {
  27039.                     $this->ui->outputData('WARNING: exclude tags are ignored in conversion');
  27040.                 }
  27041.                 if (isset($dep['min'])) {
  27042.                     $pf->addExtensionDep($dep['name'], $dep['min'], 'ge', 'yes');
  27043.                 }
  27044.                 if (isset($dep['max'])) {
  27045.                     $pf->addExtensionDep($dep['name'], $dep['max'], 'le', 'yes');
  27046.                 }
  27047.             }
  27048.         }
  27049.         $contents = $pf2->getContents();
  27050.         $release = $pf2->getReleases();
  27051.         if (isset($releases[0])) {
  27052.             return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' 
  27053.             . 'multiple extsrcrelease tags.  Using a PEAR_PackageFileManager-based script ' .
  27054.             'or the convert command is an option');
  27055.         }
  27056.         if ($configoptions = $pf2->getConfigureOptions()) {
  27057.             foreach ($configoptions as $option) {
  27058.                 $pf->addConfigureOption($option['name'], $option['prompt'],
  27059.                     isset($option['default']) ? $option['default'] : false);
  27060.             }
  27061.         }
  27062.         if (isset($release['filelist']['ignore'])) {
  27063.             return $this->raiseError('Cannot safely process "' . $packagexml . '" contains ' 
  27064.             . 'ignore tags.  Using a PEAR_PackageFileManager-based script or the convert' .
  27065.             ' command is an option');
  27066.         }
  27067.         if (isset($release['filelist']['install']) &&
  27068.               !isset($release['filelist']['install'][0])) {
  27069.             $release['filelist']['install'] = array($release['filelist']['install']);
  27070.         }
  27071.         if (isset($contents['dir']['attribs']['baseinstalldir'])) {
  27072.             $baseinstalldir = $contents['dir']['attribs']['baseinstalldir'];
  27073.         } else {
  27074.             $baseinstalldir = false;
  27075.         }
  27076.         if (!isset($contents['dir']['file'][0])) {
  27077.             $contents['dir']['file'] = array($contents['dir']['file']);
  27078.         }
  27079.         foreach ($contents['dir']['file'] as $file) {
  27080.             if ($baseinstalldir && !isset($file['attribs']['baseinstalldir'])) {
  27081.                 $file['attribs']['baseinstalldir'] = $baseinstalldir;
  27082.             }
  27083.             $processFile = $file;
  27084.             unset($processFile['attribs']);
  27085.             if (count($processFile)) {
  27086.                 foreach ($processFile as $name => $task) {
  27087.                     if ($name != $pf2->getTasksNs() . ':replace') {
  27088.                         return $this->raiseError('Cannot safely process "' . $packagexml .
  27089.                         '" contains tasks other than replace.  Using a ' .
  27090.                         'PEAR_PackageFileManager-based script is an option.');
  27091.                     }
  27092.                     $file['attribs']['replace'][] = $task;
  27093.                 }
  27094.             }
  27095.             if (!in_array($file['attribs']['role'], PEAR_Common::getFileRoles())) {
  27096.                 return $this->raiseError('Cannot safely convert "' . $packagexml .
  27097.                 '", contains custom roles.  Using a PEAR_PackageFileManager-based script ' .
  27098.                 'or the convert command is an option');
  27099.             }
  27100.             if (isset($release['filelist']['install'])) {
  27101.                 foreach ($release['filelist']['install'] as $installas) {
  27102.                     if ($installas['attribs']['name'] == $file['attribs']['name']) {
  27103.                         $file['attribs']['install-as'] = $installas['attribs']['as'];
  27104.                     }
  27105.                 }
  27106.             }
  27107.             $pf->addFile('/', $file['attribs']['name'], $file['attribs']);
  27108.         }
  27109.         if ($pf2->getChangeLog()) {
  27110.             $this->ui->outputData('WARNING: changelog is not translated to package.xml ' .
  27111.                 '1.0, use PEAR_PackageFileManager-based script if you need changelog-' .
  27112.                 'translation for package.xml 1.0');
  27113.         }
  27114.         $gen = &$pf->getDefaultGenerator();
  27115.         $gen->toPackageFile('.');
  27116.     }
  27117. }
  27118.  
  27119. ?>
  27120. PEAR-1.4.11/PEAR/Command/Registry.xml100644   1750   1750        3200 10470570063  12203 <commands version="1.0">
  27121.  <list>
  27122.   <summary>List Installed Packages In The Default Channel</summary>
  27123.   <function>doList</function>
  27124.   <shortcut>l</shortcut>
  27125.   <options>
  27126.    <channel>
  27127.     <shortopt>c</shortopt>
  27128.     <doc>list installed packages from this channel</doc>
  27129.     <arg>CHAN</arg>
  27130.    </channel>
  27131.    <allchannels>
  27132.     <shortopt>a</shortopt>
  27133.     <doc>list installed packages from all channels</doc>
  27134.    </allchannels>
  27135.   </options>
  27136.   <doc><package>
  27137. If invoked without parameters, this command lists the PEAR packages
  27138. installed in your php_dir ({config php_dir}).  With a parameter, it
  27139. lists the files in a package.
  27140. </doc>
  27141.  </list>
  27142.  <list-files>
  27143.   <summary>List Files In Installed Package</summary>
  27144.   <function>doFileList</function>
  27145.   <shortcut>fl</shortcut>
  27146.   <options />
  27147.   <doc><package>
  27148. List the files in an installed package.
  27149. </doc>
  27150.  </list-files>
  27151.  <shell-test>
  27152.   <summary>Shell Script Test</summary>
  27153.   <function>doShellTest</function>
  27154.   <shortcut>st</shortcut>
  27155.   <options />
  27156.   <doc><package> [[relation] version]
  27157. Tests if a package is installed in the system. Will exit(1) if it is not.
  27158.    <relation>   The version comparison operator. One of:
  27159.                 <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
  27160.    <version>    The version to compare with
  27161. </doc>
  27162.  </shell-test>
  27163.  <info>
  27164.   <summary>Display information about a package</summary>
  27165.   <function>doInfo</function>
  27166.   <shortcut>in</shortcut>
  27167.   <options />
  27168.   <doc><package>
  27169. Displays information about a package. The package argument may be a
  27170. local package file, an URL to a package file, or the name of an
  27171. installed package.</doc>
  27172.  </info>
  27173. </commands>PEAR-1.4.11/PEAR/Command/Registry.php100644   1750   1750      125511 10470570063  12244 <?php
  27174. /**
  27175.  * PEAR_Command_Registry (list, list-files, shell-test, info commands)
  27176.  *
  27177.  * PHP versions 4 and 5
  27178.  *
  27179.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  27180.  * that is available through the world-wide-web at the following URI:
  27181.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  27182.  * the PHP License and are unable to obtain it through the web, please
  27183.  * send a note to license@php.net so we can mail you a copy immediately.
  27184.  *
  27185.  * @category   pear
  27186.  * @package    PEAR
  27187.  * @author     Stig Bakken <ssb@php.net>
  27188.  * @author     Greg Beaver <cellog@php.net>
  27189.  * @copyright  1997-2006 The PHP Group
  27190.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  27191.  * @version    CVS: $Id: Registry.php,v 1.70 2006/01/06 04:47:36 cellog Exp $
  27192.  * @link       http://pear.php.net/package/PEAR
  27193.  * @since      File available since Release 0.1
  27194.  */
  27195.  
  27196. /**
  27197.  * base class
  27198.  */
  27199. require_once 'PEAR/Command/Common.php';
  27200.  
  27201. /**
  27202.  * PEAR commands for registry manipulation
  27203.  *
  27204.  * @category   pear
  27205.  * @package    PEAR
  27206.  * @author     Stig Bakken <ssb@php.net>
  27207.  * @author     Greg Beaver <cellog@php.net>
  27208.  * @copyright  1997-2006 The PHP Group
  27209.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  27210.  * @version    Release: 1.4.11
  27211.  * @link       http://pear.php.net/package/PEAR
  27212.  * @since      Class available since Release 0.1
  27213.  */
  27214. class PEAR_Command_Registry extends PEAR_Command_Common
  27215. {
  27216.     // {{{ properties
  27217.  
  27218.     var $commands = array(
  27219.         'list' => array(
  27220.             'summary' => 'List Installed Packages In The Default Channel',
  27221.             'function' => 'doList',
  27222.             'shortcut' => 'l',
  27223.             'options' => array(
  27224.                 'channel' => array(
  27225.                     'shortopt' => 'c',
  27226.                     'doc' => 'list installed packages from this channel',
  27227.                     'arg' => 'CHAN',
  27228.                     ),
  27229.                 'allchannels' => array(
  27230.                     'shortopt' => 'a',
  27231.                     'doc' => 'list installed packages from all channels',
  27232.                     ),
  27233.                 ),
  27234.             'doc' => '<package>
  27235. If invoked without parameters, this command lists the PEAR packages
  27236. installed in your php_dir ({config php_dir}).  With a parameter, it
  27237. lists the files in a package.
  27238. ',
  27239.             ),
  27240.         'list-files' => array(
  27241.             'summary' => 'List Files In Installed Package',
  27242.             'function' => 'doFileList',
  27243.             'shortcut' => 'fl',
  27244.             'options' => array(),
  27245.             'doc' => '<package>
  27246. List the files in an installed package.
  27247. '
  27248.             ),
  27249.         'shell-test' => array(
  27250.             'summary' => 'Shell Script Test',
  27251.             'function' => 'doShellTest',
  27252.             'shortcut' => 'st',
  27253.             'options' => array(),
  27254.             'doc' => '<package> [[relation] version]
  27255. Tests if a package is installed in the system. Will exit(1) if it is not.
  27256.    <relation>   The version comparison operator. One of:
  27257.                 <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
  27258.    <version>    The version to compare with
  27259. '),
  27260.         'info' => array(
  27261.             'summary'  => 'Display information about a package',
  27262.             'function' => 'doInfo',
  27263.             'shortcut' => 'in',
  27264.             'options'  => array(),
  27265.             'doc'      => '<package>
  27266. Displays information about a package. The package argument may be a
  27267. local package file, an URL to a package file, or the name of an
  27268. installed package.'
  27269.             )
  27270.         );
  27271.  
  27272.     // }}}
  27273.     // {{{ constructor
  27274.  
  27275.     /**
  27276.      * PEAR_Command_Registry constructor.
  27277.      *
  27278.      * @access public
  27279.      */
  27280.     function PEAR_Command_Registry(&$ui, &$config)
  27281.     {
  27282.         parent::PEAR_Command_Common($ui, $config);
  27283.     }
  27284.  
  27285.     // }}}
  27286.  
  27287.     // {{{ doList()
  27288.  
  27289.     function _sortinfo($a, $b)
  27290.     {
  27291.         $apackage = isset($a['package']) ? $a['package'] : $a['name'];
  27292.         $bpackage = isset($b['package']) ? $b['package'] : $b['name'];
  27293.         return strcmp($apackage, $bpackage);
  27294.     }
  27295.  
  27296.     function doList($command, $options, $params)
  27297.     {
  27298.         if (isset($options['allchannels'])) {
  27299.             return $this->doListAll($command, array(), $params);
  27300.         }
  27301.         $reg = &$this->config->getRegistry();
  27302.         if (count($params) == 1) {
  27303.             return $this->doFileList($command, $options, $params);
  27304.         }
  27305.         if (isset($options['channel'])) {
  27306.             if ($reg->channelExists($options['channel'])) {
  27307.                 $channel = $reg->channelName($options['channel']);
  27308.             } else {
  27309.                 return $this->raiseError('Channel "' . $options['channel'] .'" does not exist');
  27310.             }
  27311.         } else {
  27312.             $channel = $this->config->get('default_channel');
  27313.         }
  27314.         $installed = $reg->packageInfo(null, null, $channel);
  27315.         usort($installed, array(&$this, '_sortinfo'));
  27316.         $i = $j = 0;
  27317.         $data = array(
  27318.             'caption' => 'Installed packages, channel ' .
  27319.                 $channel . ':',
  27320.             'border' => true,
  27321.             'headline' => array('Package', 'Version', 'State')
  27322.             );
  27323.         foreach ($installed as $package) {
  27324.             $pobj = $reg->getPackage(isset($package['package']) ?
  27325.                                         $package['package'] : $package['name'], $channel);
  27326.             $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(),
  27327.                                     $pobj->getState() ? $pobj->getState() : null);
  27328.         }
  27329.         if (count($installed)==0) {
  27330.             $data = '(no packages installed from channel ' . $channel . ')';
  27331.         }
  27332.         $this->ui->outputData($data, $command);
  27333.         return true;
  27334.     }
  27335.     
  27336.     function doListAll($command, $options, $params)
  27337.     {
  27338.         $reg = &$this->config->getRegistry();
  27339.         $installed = $reg->packageInfo(null, null, null);
  27340.         foreach ($installed as $channel => $packages) {
  27341.             usort($packages, array($this, '_sortinfo'));
  27342.             $i = $j = 0;
  27343.             $data = array(
  27344.                 'caption' => 'Installed packages, channel ' . $channel . ':',
  27345.                 'border' => true,
  27346.                 'headline' => array('Package', 'Version', 'State')
  27347.                 );
  27348.             foreach ($packages as $package) {
  27349.                 $pobj = $reg->getPackage(isset($package['package']) ?
  27350.                                             $package['package'] : $package['name'], $channel);
  27351.                 $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(),
  27352.                                         $pobj->getState() ? $pobj->getState() : null);
  27353.             }
  27354.             if (count($packages)==0) {
  27355.                 $data = array(
  27356.                     'caption' => 'Installed packages, channel ' . $channel . ':',
  27357.                     'border' => true,
  27358.                     'data' => array(array('(no packages installed)')),
  27359.                     );
  27360.             }
  27361.             $this->ui->outputData($data, $command);
  27362.         }
  27363.         return true;
  27364.     }
  27365.     
  27366.     function doFileList($command, $options, $params)
  27367.     {
  27368.         if (count($params) != 1) {
  27369.             return $this->raiseError('list-files expects 1 parameter');
  27370.         }
  27371.         $reg = &$this->config->getRegistry();
  27372.         if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0],
  27373.               'r'))) {
  27374.             @fclose($fp);
  27375.             if (!class_exists('PEAR_PackageFile')) {
  27376.                 require_once 'PEAR/PackageFile.php';
  27377.             }
  27378.             $pkg = &new PEAR_PackageFile($this->config, $this->_debug);
  27379.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27380.             $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  27381.             PEAR::staticPopErrorHandling();
  27382.             $headings = array('Package File', 'Install Path');
  27383.             $installed = false;
  27384.         } else {
  27385.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27386.             $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  27387.             PEAR::staticPopErrorHandling();
  27388.             if (PEAR::isError($parsed)) {
  27389.                 return $this->raiseError($parsed);
  27390.             }
  27391.             $info = &$reg->getPackage($parsed['package'], $parsed['channel']);
  27392.             $headings = array('Type', 'Install Path');
  27393.             $installed = true;
  27394.         }
  27395.         if (PEAR::isError($info)) {
  27396.             return $this->raiseError($info);
  27397.         }
  27398.         if ($info === null) {
  27399.             return $this->raiseError("`$params[0]' not installed");
  27400.         }
  27401.         $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ?
  27402.             $info->getFilelist() : $info->getContents();
  27403.         if ($installed) {
  27404.             $caption = 'Installed Files For ' . $params[0];
  27405.         } else {
  27406.             $caption = 'Contents of ' . basename($params[0]);
  27407.         }
  27408.         $data = array(
  27409.             'caption' => $caption,
  27410.             'border' => true,
  27411.             'headline' => $headings);
  27412.         if ($info->getPackagexmlVersion() == '1.0' || $installed) {
  27413.             foreach ($list as $file => $att) {
  27414.                 if ($installed) {
  27415.                     if (empty($att['installed_as'])) {
  27416.                         continue;
  27417.                     }
  27418.                     $data['data'][] = array($att['role'], $att['installed_as']);
  27419.                 } else {
  27420.                     if (isset($att['baseinstalldir']) && !in_array($att['role'],
  27421.                           array('test', 'data', 'doc'))) {
  27422.                         $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR .
  27423.                             $file;
  27424.                     } else {
  27425.                         $dest = $file;
  27426.                     }
  27427.                     switch ($att['role']) {
  27428.                         case 'test':
  27429.                         case 'data':
  27430.                         case 'doc':
  27431.                             $role = $att['role'];
  27432.                             if ($role == 'test') {
  27433.                                 $role .= 's';
  27434.                             }
  27435.                             $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR .
  27436.                                 $info->getPackage() . DIRECTORY_SEPARATOR . $dest;
  27437.                             break;
  27438.                         case 'php':
  27439.                         default:
  27440.                             $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR .
  27441.                                 $dest;
  27442.                     }
  27443.                     $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
  27444.                     $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
  27445.                                                     array(DIRECTORY_SEPARATOR,
  27446.                                                           DIRECTORY_SEPARATOR,
  27447.                                                           DIRECTORY_SEPARATOR),
  27448.                                                     $dest);
  27449.                     $file = preg_replace('!/+!', '/', $file);
  27450.                     $data['data'][] = array($file, $dest);
  27451.                 }
  27452.             }
  27453.         } else { // package.xml 2.0, not installed
  27454.             if (!isset($list['dir']['file'][0])) {
  27455.                 $list['dir']['file'] = array($list['dir']['file']);
  27456.             }
  27457.             foreach ($list['dir']['file'] as $att) {
  27458.                 $att = $att['attribs'];
  27459.                 $file = $att['name'];
  27460.                 $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config);
  27461.                 $role->setup($this, $info, $att, $file);
  27462.                 if (!$role->isInstallable()) {
  27463.                     $dest = '(not installable)';
  27464.                 } else {
  27465.                     $dest = $role->processInstallation($info, $att, $file, '');
  27466.                     if (PEAR::isError($dest)) {
  27467.                         $dest = '(Unknown role "' . $att['role'] . ')';
  27468.                     } else {
  27469.                         list(,, $dest) = $dest;
  27470.                     }
  27471.                 }
  27472.                 $data['data'][] = array($file, $dest);
  27473.             }
  27474.         }
  27475.         $this->ui->outputData($data, $command);
  27476.         return true;
  27477.     }
  27478.  
  27479.     // }}}
  27480.     // {{{ doShellTest()
  27481.  
  27482.     function doShellTest($command, $options, $params)
  27483.     {
  27484.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  27485.         $reg = &$this->config->getRegistry();
  27486.         $info = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
  27487.         if (PEAR::isError($info)) {
  27488.             exit(1); // invalid package name
  27489.         }
  27490.         $package = $info['package'];
  27491.         $channel = $info['channel'];
  27492.         // "pear shell-test Foo"
  27493.         if (!$reg->packageExists($package, $channel)) {
  27494.             if ($channel == 'pecl.php.net') {
  27495.                 if ($reg->packageExists($package, 'pear.php.net')) {
  27496.                     $channel = 'pear.php.net'; // magically change channels for extensions
  27497.                 }
  27498.             }
  27499.         }
  27500.         if (sizeof($params) == 1) {
  27501.             if (!$reg->packageExists($package, $channel)) {
  27502.                 exit(1);
  27503.             }
  27504.             // "pear shell-test Foo 1.0"
  27505.         } elseif (sizeof($params) == 2) {
  27506.             $v = $reg->packageInfo($package, 'version', $channel);
  27507.             if (!$v || !version_compare("$v", "{$params[1]}", "ge")) {
  27508.                 exit(1);
  27509.             }
  27510.             // "pear shell-test Foo ge 1.0"
  27511.         } elseif (sizeof($params) == 3) {
  27512.             $v = $reg->packageInfo($package, 'version', $channel);
  27513.             if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) {
  27514.                 exit(1);
  27515.             }
  27516.         } else {
  27517.             $this->popErrorHandling();
  27518.             $this->raiseError("$command: expects 1 to 3 parameters");
  27519.             exit(1);
  27520.         }
  27521.     }
  27522.  
  27523.     // }}}
  27524.     // {{{ doInfo
  27525.  
  27526.     function doInfo($command, $options, $params)
  27527.     {
  27528.         if (count($params) != 1) {
  27529.             return $this->raiseError('pear info expects 1 parameter');
  27530.         }
  27531.         $info = false;
  27532.         $reg = &$this->config->getRegistry();
  27533.         if ((@is_file($params[0]) && !is_dir($params[0])) || $fp = @fopen($params[0], 'r')) {
  27534.             @fclose($fp);
  27535.             if (!class_exists('PEAR_PackageFile')) {
  27536.                 require_once 'PEAR/PackageFile.php';
  27537.             }
  27538.             $pkg = &new PEAR_PackageFile($this->config, $this->_debug);
  27539.             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
  27540.             $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
  27541.             PEAR::staticPopErrorHandling();
  27542.             if (PEAR::isError($obj)) {
  27543.                 $uinfo = $obj->getUserInfo();
  27544.                 if (is_array($uinfo)) {
  27545.                     foreach ($uinfo as $message) {
  27546.                         if (is_array($message)) {
  27547.                             $message = $message['message'];
  27548.                         }
  27549.                         $this->ui->outputData($message);
  27550.                     }
  27551.                 }
  27552.                 return $this->raiseError($obj);
  27553.             }
  27554.             if ($obj->getPackagexmlVersion() == '1.0') {
  27555.                 $info = $obj->toArray();
  27556.             } else {
  27557.                 return $this->_doInfo2($command, $options, $params, $obj, false